diff --git a/src/client/client_cli.c b/src/client/client_cli.c index 714bd6e..e96ae53 100644 --- a/src/client/client_cli.c +++ b/src/client/client_cli.c @@ -205,6 +205,16 @@ int main(int argc, char *argv[]) { return 1; } + if (config->use_incremental && config->use_chunk_serialization) { + fprintf(stderr, "Error: --incremental is not supported with -s (chunk serialization)\n"); + return 1; + } + + if (config->use_incremental && !config->use_metadata) { + log_message(LOG_LEVEL_INFO, "Enabling metadata preservation for --incremental"); + config->use_metadata = true; + } + if (config->use_multithreading) return send_files_multithreaded(config); return send_files(config); diff --git a/src/client/client_send.c b/src/client/client_send.c index 255e834..c0ee3b2 100644 --- a/src/client/client_send.c +++ b/src/client/client_send.c @@ -41,13 +41,16 @@ int send_chunk(Client *client, Chunk *chunk, Config *config) { if (!send_n_data(client->file_descriptor, &mtime, sizeof(mtime))) return -1; Status s; if (!receive_status(client->file_descriptor, &s)) return -1; + if (s == STATUS_ERROR) { log_message(LOG_LEVEL_ERROR, "Server reported error for file"); return -1; } if (s == STATUS_OK) continue; - if (s != STATUS_NEXT) return -1; + if (s != STATUS_NEXT) { log_message(LOG_LEVEL_ERROR, "Unexpected server status"); return -1; } + if (!file_send_sendfile_no_path(chunk->items[i], client->file_descriptor, config->use_metadata)) + return -1; } else { if (!send_status(client->file_descriptor, STATUS_NEXT)) return -1; + if (!file_send_sendfile(chunk->items[i], client->file_descriptor, config->use_metadata)) + return -1; } - if (!file_send_sendfile(chunk->items[i], client->file_descriptor, config->use_metadata)) - return -1; } } else { for (int i = 0; i < chunk->element_count; i++) { @@ -60,8 +63,9 @@ int send_chunk(Client *client, Chunk *chunk, Config *config) { if (!send_n_data(client->file_descriptor, &mtime, sizeof(mtime))) return -1; Status s; if (!receive_status(client->file_descriptor, &s)) return -1; + if (s == STATUS_ERROR) { log_message(LOG_LEVEL_ERROR, "Server reported error for file"); return -1; } if (s == STATUS_OK) continue; - if (s != STATUS_NEXT) return -1; + if (s != STATUS_NEXT) { log_message(LOG_LEVEL_ERROR, "Unexpected server status"); return -1; } if (!file_send_single_calls_no_path(chunk->items[i], client->file_descriptor, config->use_metadata, config->use_compression ? config->compression_level : 0)) diff --git a/src/shared/config.h b/src/shared/config.h index 6af810b..b581de7 100644 --- a/src/shared/config.h +++ b/src/shared/config.h @@ -35,7 +35,7 @@ typedef struct Config { bool use_incremental; } Config; -#define PROTOCOL_VERSION "1.0.0" +#define PROTOCOL_VERSION "1.1.0" #define DEFAULT_CHUNK_SIZE (10 * 1024 * 1024) Config *config_create(char *version, char *send_directory, diff --git a/src/shared/file.c b/src/shared/file.c index f04f2e2..fd403d7 100644 --- a/src/shared/file.c +++ b/src/shared/file.c @@ -97,37 +97,81 @@ bool file_load_data(File *file) { } bool file_send_single_calls_no_path(File *file, int file_descriptor, bool use_metadata, int compression_level) { + Data *data_to_send = file->data; + Data *compressed_data = NULL; if (compression_level > 0) { - Data *compressed_data = data_compress(file->data, compression_level); + compressed_data = data_compress(file->data, compression_level); if (compressed_data == NULL) { log_message(LOG_LEVEL_ERROR, "Failed to compress file data"); return false; } - data_destroy(file->data); - file->data = compressed_data; + data_to_send = compressed_data; } + if (use_metadata && !metadata_send(file_descriptor, file->metadata)) { + data_destroy(compressed_data); + return false; + } + if (!send_data(file_descriptor, data_to_send)) { + data_destroy(compressed_data); + return false; + } + data_destroy(compressed_data); + return true; +} + +bool file_send_sendfile_no_path(File *file, int file_descriptor, bool use_metadata) { if (use_metadata && !metadata_send(file_descriptor, file->metadata)) return false; - if (!send_data(file_descriptor, file->data)) return false; + + int fd = open(file->path, O_RDONLY); + if (fd == -1) { + perror("Could not open file for sendfile"); + return false; + } + + unsigned long long file_size = file->data->size; + if (!send_n_data(file_descriptor, &file_size, sizeof(unsigned long long))) { + close(fd); + return false; + } + + off_t offset = 0; + while (offset < file_size) { + ssize_t sent = sendfile(file_descriptor, fd, &offset, file_size - offset); + if (sent == -1) { + perror("sendfile failed"); + close(fd); + return false; + } + } + + close(fd); return true; } bool file_send_single_calls(File *file, int file_descriptor, bool use_metadata, int compression_level) { + Data *data_to_send = file->data; + Data *compressed_data = NULL; if (compression_level > 0) { - Data *compressed_data = data_compress(file->data, compression_level); + compressed_data = data_compress(file->data, compression_level); if (compressed_data == NULL) { log_message(LOG_LEVEL_ERROR, "Failed to compress file data"); return false; } - data_destroy(file->data); - if (compressed_data == NULL) { - log_message(LOG_LEVEL_ERROR, "Compression failed in file_send_single_calls"); - exit(EXIT_FAILURE); - } - file->data = compressed_data; + data_to_send = compressed_data; } - if (!send_str(file_descriptor, file->path)) return false; - if (use_metadata && !metadata_send(file_descriptor, file->metadata)) return false; - if (!send_data(file_descriptor, file->data)) return false; + if (!send_str(file_descriptor, file->path)) { + data_destroy(compressed_data); + return false; + } + if (use_metadata && !metadata_send(file_descriptor, file->metadata)) { + data_destroy(compressed_data); + return false; + } + if (!send_data(file_descriptor, data_to_send)) { + data_destroy(compressed_data); + return false; + } + data_destroy(compressed_data); return true; } diff --git a/src/shared/file.h b/src/shared/file.h index 4f28d06..feb8fbc 100644 --- a/src/shared/file.h +++ b/src/shared/file.h @@ -27,6 +27,7 @@ File *file_receive(Config *config, int file_descriptor); bool file_send_single_calls(File *file, int file_descriptor, bool use_metadata, int compression_level); bool file_send_single_calls_no_path(File *file, int file_descriptor, bool use_metadata, int compression_level); bool file_send_sendfile(File *file, int file_descriptor, bool use_metadata); +bool file_send_sendfile_no_path(File *file, int file_descriptor, bool use_metadata); size_t file_content_to_buffer(File *file); FileMetadata *file_metadata_create(struct stat *stats); void file_metadata_destroy(void *metadata);