Files
FastSyncAi/src/utils.c
T
Theo Tappe bacb61f6ec Fix: Add missing checksum field to file_meta_t and file_task_t structs
The file_meta_t and file_task_t structs were missing the checksum field
that was being used in both client and server code, causing a compilation
error. Added uint64_t checksum to both structs and updated wq_push
declaration to match implementation.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-24 12:40:23 +02:00

131 lines
3.5 KiB
C

#include "common.h"
ssize_t readn(int fd, void *vptr, size_t n) {
size_t nleft;
ssize_t nread;
char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
if ((nread = read(fd, ptr, nleft)) < 0) {
if (errno == EINTR) {
nread = 0; /* call read() again */
} else {
return -1;
}
} else if (nread == 0) {
break; /* EOF */
}
nleft -= nread;
ptr += nread;
}
return n - nleft;
}
ssize_t writen(int fd, const void *vptr, size_t n) {
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
if ((nwritten = write(fd, ptr, nleft)) <= 0) {
if (nwritten < 0 && errno == EINTR)
nwritten = 0; /* and call write() again */
else
return -1; /* error */
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
}
// ─── Simple path creation ───────────────────────────────────────────────
int make_path(const char *path, mode_t mode) {
char tmp[2048], *p = NULL;
size_t len;
snprintf(tmp, sizeof(tmp), "%s", path);
len = strlen(tmp);
if (tmp[len - 1] == '/')
tmp[len - 1] = '\0';
for (p = tmp + 1; *p; p++)
if (*p == '/') {
*p = '\0';
if (mkdir(tmp, mode) == -1 && errno != EEXIST)
return -1;
*p = '/';
}
if (mkdir(tmp, mode) == -1 && errno != EEXIST)
return -1;
return 0;
}
// ─── Work-Queue (client-side, thread-safe) ───────────────────────────────────
void wq_init(work_queue_t *q) {
q->head = NULL;
q->tail = NULL;
q->done = 0;
q->error = 0;
pthread_mutex_init(&q->lock, NULL);
pthread_cond_init(&q->cond, NULL);
}
void wq_push(work_queue_t *q, const char *full_path, const char *rel_path, uint64_t file_size, uint64_t checksum) {
file_task_t *t = malloc(sizeof(file_task_t));
if (!t) { perror("wq_push malloc"); return; }
snprintf(t->full_path, sizeof(t->full_path), "%s", full_path);
snprintf(t->rel_path, sizeof(t->rel_path), "%s", rel_path);
t->file_size = file_size;
t->checksum = checksum;
t->next = NULL;
pthread_mutex_lock(&q->lock);
if (q->tail) {
q->tail->next = t;
} else {
q->head = t;
}
q->tail = t;
pthread_cond_signal(&q->cond);
pthread_mutex_unlock(&q->lock);
}
/* Returns NULL when queue is empty AND done=1 (no more work ever). */
file_task_t *wq_pop(work_queue_t *q) {
pthread_mutex_lock(&q->lock);
while (q->head == NULL && !q->done) {
pthread_cond_wait(&q->cond, &q->lock);
}
file_task_t *t = q->head;
if (t) {
q->head = t->next;
if (!q->head) q->tail = NULL;
}
pthread_mutex_unlock(&q->lock);
return t; /* NULL means done */
}
void wq_finish(work_queue_t *q) {
pthread_mutex_lock(&q->lock);
q->done = 1;
pthread_cond_broadcast(&q->cond); /* wake ALL waiting workers */
pthread_mutex_unlock(&q->lock);
}
void wq_destroy(work_queue_t *q) {
/* drain any leftover tasks */
file_task_t *t = q->head;
while (t) {
file_task_t *next = t->next;
free(t);
t = next;
}
pthread_mutex_destroy(&q->lock);
pthread_cond_destroy(&q->cond);
}