refactor: quality cleanup — table-driven CLI, file.c split, scanner helpers, unified error reporting #216

Merged
TapTap merged 7 commits from refactor/quality-cleanup into dev 2026-09-01 20:39:31 +02:00
Showing only changes of commit ae95211a05 - Show all commits
+39 -42
View File
@@ -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 /* Progress-reporting thread for multithreaded send. Runs in parallel with
the scanner/loader/sender threads and prints periodic progress to stderr. */ the scanner/loader/sender threads and prints periodic progress to stderr. */
static int progress_thread_fn(void* arg) { static int progress_thread_fn(void* arg) {
@@ -551,20 +562,14 @@ static int progress_thread_fn(void* arg) {
mtx_unlock(&context->mutex_progress); mtx_unlock(&context->mutex_progress);
if (done) { if (done) {
time_t now = time(NULL); print_transfer_progress(total, start, "Done.\n");
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);
break; break;
} }
time_t now = time(NULL); time_t now = time(NULL);
if (now - last_progress >= 1) { if (now - last_progress >= 1) {
last_progress = now; last_progress = now;
double elapsed = difftime(now, start); print_transfer_progress(total, 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);
} }
struct timespec ts = {0, 100 * 1000000L}; /* 100 ms */ 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_init(&session, client->file_descriptor, client->file_descriptor);
protocol_session_set_ssl(&session, (SSL*)client->ssl); protocol_session_set_ssl(&session, (SSL*)client->ssl);
protocol_session_bind(&session); protocol_session_bind(&session);
if (!config_send(client->file_descriptor, config)) { int ret = 1;
disconnect_transfer_client(client); DirectoryScanner* scanner = NULL;
protocol_session_unbind(); ArrayList* manifest = NULL;
return 1; if (!config_send(client->file_descriptor, config))
} goto send_fail;
ScannerOptions scanner_options = scanner_options_from_config(config, 0); ScannerOptions scanner_options = scanner_options_from_config(config, 0);
DirectoryScanner* scanner = scanner = directory_scanner_create_with_options(config->send_directory, &scanner_options);
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; Chunk* current_chunk;
unsigned long long total_bytes = 0; unsigned long long total_bytes = 0;
int total_files = 0; int total_files = 0;
time_t last_progress = 0; time_t last_progress = 0;
time_t start = time(NULL); 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) { while ((current_chunk = directory_scanner_next(scanner)) != NULL) {
unsigned long long chunk_bytes = 0; unsigned long long chunk_bytes = 0;
for (int i = 0; i < current_chunk->element_count; i++) { for (int i = 0; i < current_chunk->element_count; i++) {
@@ -621,16 +618,21 @@ int send_files(Config* config) {
goto send_fail; goto send_fail;
} }
if (!config->use_sendfile) { if (!config->use_sendfile) {
bool load_ok = true;
for (int i = 0; i < current_chunk->element_count; i++) { for (int i = 0; i < current_chunk->element_count; i++) {
File* f = current_chunk->items[i]; File* f = current_chunk->items[i];
if (f->data->size > STREAM_THRESHOLD) if (f->data->size > STREAM_THRESHOLD)
continue; continue;
if (!file_load_data(f)) { if (!file_load_data(f)) {
log_message(LOG_LEVEL_ERROR, "Failed to load file data"); log_message(LOG_LEVEL_ERROR, "Failed to load file data");
chunk_destroy(current_chunk); load_ok = false;
goto send_fail; break;
} }
} }
if (!load_ok) {
chunk_destroy(current_chunk);
goto send_fail;
}
} }
if (send_chunk(client, current_chunk, config) != 0) { if (send_chunk(client, current_chunk, config) != 0) {
log_message(LOG_LEVEL_ERROR, "Failed to send chunk"); log_message(LOG_LEVEL_ERROR, "Failed to send chunk");
@@ -645,10 +647,7 @@ int send_files(Config* config) {
time_t now = time(NULL); time_t now = time(NULL);
if (now - last_progress >= 1) { if (now - last_progress >= 1) {
last_progress = now; last_progress = now;
double elapsed = difftime(now, start); print_transfer_progress(total_bytes, 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); chunk_destroy(current_chunk);
@@ -665,28 +664,26 @@ int send_files(Config* config) {
manifest = NULL; manifest = NULL;
} }
bool ok = finalize_transfer(client); bool ok = finalize_transfer(client);
double elapsed_total = difftime(time(NULL), start); if (config->show_progress)
if (config->show_progress) { print_transfer_progress(total_bytes, start, "Done.\n");
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->stats) { if (config->stats) {
double elapsed_total = difftime(time(NULL), start);
double rate = elapsed_total > 0 ? total_bytes / (1048576.0 * elapsed_total) : 0; 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, fprintf(stderr, "Stats: %d files, %.1f MB, %.1f MB/s\n", total_files, total_bytes / 1048576.0,
rate); rate);
} }
directory_scanner_destroy(scanner); ret = ok ? 0 : 1;
disconnect_transfer_client(client);
protocol_session_unbind();
return ok ? 0 : 1;
send_fail: 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) if (manifest)
array_list_delete(manifest); array_list_delete(manifest);
directory_scanner_destroy(scanner); if (scanner)
directory_scanner_destroy(scanner);
disconnect_transfer_client(client); disconnect_transfer_client(client);
protocol_session_unbind(); protocol_session_unbind();
return 1; return ret;
} }
int send_files_multithreaded(Config* config) { int send_files_multithreaded(Config* config) {