refactor: quality cleanup — table-driven CLI, file.c split, scanner helpers, unified error reporting #216
+39
-42
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user