refactor: merge File/FileReceive, add optional metadata transfer with -M flag

- Remove FileReceive struct; use File everywhere with nullable FileMetadata*
- Remove struct stat from File; file size lives in Data->size (data_create_reserve)
- Add FileMetadata struct (mode, uid, gid, mtime) sent conditionally over wire
- Add -M / --preserve flag to client
- Restore permissions, ownership, timestamps on disk write
- Wire format uses per-file present flag for metadata (zero overhead when off)
This commit is contained in:
2026-07-05 20:21:46 +02:00
parent e7c23c135b
commit 4a1e666365
17 changed files with 285 additions and 165 deletions
+61 -25
View File
@@ -11,15 +11,13 @@
#include "log.h"
#include "socket.h"
File *file_create(const char *path, struct stat *stats) {
File *file_create(const char *path) {
File *file = (File *)malloc(sizeof(File));
if (file == NULL) {
perror("FATAL ERROR: Could not allocate memory for file struct");
exit(EXIT_FAILURE);
}
file->stats = *stats;
int path_len = strlen(path);
file->path = (char *)malloc(path_len + 1);
if (file->path == NULL) {
@@ -29,7 +27,8 @@ File *file_create(const char *path, struct stat *stats) {
}
strcpy(file->path, path);
file->data = NULL;
file->data = data_create_reserve(0);
file->metadata = NULL;
return file;
}
@@ -39,15 +38,40 @@ void file_destroy(void *item) {
File *file = (File *)item;
data_destroy(file->data);
file->data = NULL;
file_metadata_destroy(file->metadata);
file->metadata = NULL;
free(file->path);
file->path = NULL;
free(file);
}
FileMetadata *file_metadata_create(struct stat *stats) {
FileMetadata *m = malloc(sizeof(FileMetadata));
if (m == NULL) {
perror("FATAL ERROR: Could not allocate memory for file metadata");
exit(EXIT_FAILURE);
}
m->mode = stats->st_mode;
m->uid = stats->st_uid;
m->gid = stats->st_gid;
m->mtime_sec = stats->st_mtime;
#ifdef __linux__
m->mtime_nsec = stats->st_mtim.tv_nsec;
#else
m->mtime_nsec = 0;
#endif
return m;
}
void file_metadata_destroy(void *metadata) {
free(metadata);
}
void file_load_data(File *file) {
if (file == NULL)
return;
file->data = data_create_empty(file->stats.st_size);
if (file->data->data == NULL)
file->data->data = malloc(file->data->size);
printf("%ld is file big", file->data->size);
size_t bytes_read = file_content_to_buffer(file);
if (bytes_read != file->data->size) {
@@ -62,8 +86,38 @@ void file_print(void *item) {
printf("%s\n", ((File *)item)->path);
}
static void metadata_send(int file_descriptor, FileMetadata *m) {
if (m == NULL) {
int zero = 0;
send_n_data(file_descriptor, &zero, sizeof(int));
return;
}
int present = 1;
send_n_data(file_descriptor, &present, sizeof(int));
send_n_data(file_descriptor, &m->mode, sizeof(mode_t));
send_n_data(file_descriptor, &m->uid, sizeof(uid_t));
send_n_data(file_descriptor, &m->gid, sizeof(gid_t));
send_n_data(file_descriptor, &m->mtime_sec, sizeof(time_t));
send_n_data(file_descriptor, &m->mtime_nsec, sizeof(long));
}
FileMetadata *file_receive_metadata(int file_descriptor) {
int present;
receive_n_data(file_descriptor, &present, sizeof(int));
if (!present)
return NULL;
FileMetadata *m = malloc(sizeof(FileMetadata));
receive_n_data(file_descriptor, &m->mode, sizeof(mode_t));
receive_n_data(file_descriptor, &m->uid, sizeof(uid_t));
receive_n_data(file_descriptor, &m->gid, sizeof(gid_t));
receive_n_data(file_descriptor, &m->mtime_sec, sizeof(time_t));
receive_n_data(file_descriptor, &m->mtime_nsec, sizeof(long));
return m;
}
void file_send_single_calls(File *file, int file_descriptor) {
send_str(file_descriptor, file->path);
metadata_send(file_descriptor, file->metadata);
printf("Sending File: %ld", file->data->size);
send_data(file_descriptor, file->data->data, file->data->size);
}
@@ -75,29 +129,11 @@ size_t file_content_to_buffer(File *file) {
return 0;
}
size_t bytes_read =
fread(file->data->data, 1, file->stats.st_size, file_pointer);
if (bytes_read != (size_t)file->stats.st_size) {
fread(file->data->data, 1, file->data->size, file_pointer);
if (bytes_read != (size_t)file->data->size) {
perror("Read to many or to less bytes from File!");
return 0;
}
fclose(file_pointer);
return bytes_read;
}
FileReceive *file_receive_create(char *path, Data *data) {
FileReceive *file = malloc(sizeof(FileReceive));
file->path = path;
file->data = data;
return file;
}
void file_receive_destroy(void *file_receive) {
if (file_receive == NULL)
return;
FileReceive *file = (FileReceive *)file_receive;
data_destroy(file->data);
free(file->path);
free(file);
}