From 4c37f4872d709a04c5b5d0cc7aa342eae26c8643 Mon Sep 17 00:00:00 2001 From: grayTerminal-sh Date: Sun, 19 Jul 2026 16:51:06 +0200 Subject: [PATCH] feat: add verified evidence file copy --- Makefile | 17 +- include/core/evidence_copy.h | 199 +++ labfy-investigation | Bin 383160 -> 402824 bytes src/core/evidence_copy.c | 1572 +++++++++++++++++ tests/test_evidence_copy | Bin 0 -> 78264 bytes tests/test_evidence_copy.c | 3194 ++++++++++++++++++++++++++++++++++ 6 files changed, 4979 insertions(+), 3 deletions(-) create mode 100644 include/core/evidence_copy.h create mode 100644 src/core/evidence_copy.c create mode 100755 tests/test_evidence_copy create mode 100644 tests/test_evidence_copy.c diff --git a/Makefile b/Makefile index a918eac..0c073bd 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,6 @@ TEST_TRANSACTION = tests/test_transaction TEST_ERROR = tests/test_error TEST_INVESTIGATION_RECORD = tests/test_investigation_record TEST_EVIDENCE_RECORD := tests/test_evidence_record -TEST_EVIDENCE_RECORD := tests/test_evidence_record TEST_INVESTIGATION_DAO := tests/test_investigation_dao TEST_EVIDENCE_DAO := tests/test_evidence_dao TEST_INVESTIGATION_SESSION := tests/test_investigation_session @@ -53,6 +52,7 @@ TEST_TOOL_TASK := tests/test_tool_task TEST_TOOL_CATALOG := tests/test_tool_catalog TEST_TOOL_INITIALIZER := tests/test_tool_initializer TEST_FILE_HASH := tests/test_file_hash +TEST_EVIDENCE_COPY := tests/test_evidence_copy all: $(TARGET) @@ -220,6 +220,14 @@ $(TEST_FILE_HASH): \ -DFILE_HASH_ENABLE_TEST_HOOKS \ $^ -o $@ $(TEST_LDFLAGS) +$(TEST_EVIDENCE_COPY): \ + tests/test_evidence_copy.c \ + src/core/evidence_copy.c \ + src/core/file_hash.c + $(CC) $(TEST_CFLAGS) \ + -DEVIDENCE_COPY_ENABLE_TEST_HOOKS \ + $^ -o $@ $(TEST_LDFLAGS) + test: \ $(TEST_NODE) \ $(TEST_TREE_MODEL) \ @@ -241,7 +249,8 @@ test: \ $(TEST_TOOL_TASK) \ $(TEST_TOOL_CATALOG) \ $(TEST_TOOL_INITIALIZER) \ - $(TEST_FILE_HASH) + $(TEST_FILE_HASH) \ + $(TEST_EVIDENCE_COPY) @echo "Exécution des tests..." @./$(TEST_NODE) @./$(TEST_TREE_MODEL) @@ -264,6 +273,7 @@ test: \ @$(TEST_TOOL_CATALOG) @$(TEST_TOOL_INITIALIZER) @$(TEST_FILE_HASH) + @$(TEST_EVIDENCE_COPY) @echo "Tous les tests sont valides." %.o: %.c @@ -294,7 +304,8 @@ clean: $(TEST_TOOL_TASK) \ $(TEST_TOOL_CATALOG) \ $(TEST_TOOL_INITIALIZER) \ - $(TEST_FILE_HASH) + $(TEST_FILE_HASH) \ + $(TEST_EVIDENCE_COPY) .PHONY: clean run test diff --git a/include/core/evidence_copy.h b/include/core/evidence_copy.h new file mode 100644 index 0000000..c8a2eb7 --- /dev/null +++ b/include/core/evidence_copy.h @@ -0,0 +1,199 @@ +/****************************************************************************** + * @file evidence_copy.h + * @brief Copie sûre et vérifiée des fichiers de preuve. + ******************************************************************************/ + +#ifndef LABFY_INVESTIGATION_EVIDENCE_COPY_H +#define LABFY_INVESTIGATION_EVIDENCE_COPY_H + +#include +#include + +/** + * @brief Catégories d’erreurs du module EvidenceCopy. + */ +typedef enum +{ + EVIDENCE_COPY_ERROR_INVALID_ARGUMENT, + EVIDENCE_COPY_ERROR_SOURCE_NOT_FOUND, + EVIDENCE_COPY_ERROR_SOURCE_NOT_REGULAR, + EVIDENCE_COPY_ERROR_DESTINATION_INVALID, + EVIDENCE_COPY_ERROR_DESTINATION_EXISTS, + EVIDENCE_COPY_ERROR_OPEN_SOURCE, + EVIDENCE_COPY_ERROR_CREATE_DESTINATION, + EVIDENCE_COPY_ERROR_READ, + EVIDENCE_COPY_ERROR_WRITE, + EVIDENCE_COPY_ERROR_SYNC, + EVIDENCE_COPY_ERROR_HASH, + EVIDENCE_COPY_ERROR_VERIFY, + EVIDENCE_COPY_ERROR_CANCELLED, + EVIDENCE_COPY_ERROR_MEMORY, + EVIDENCE_COPY_ERROR_CLEANUP +} EvidenceCopyError; + +/** + * @brief Domaine d’erreurs du module EvidenceCopy. + */ +#define EVIDENCE_COPY_ERROR \ + evidence_copy_error_quark() + +/** + * @brief Retourne le domaine d’erreurs du module EvidenceCopy. + */ +GQuark evidence_copy_error_quark(void); + +/** + * @brief Résultat opaque d’une copie de preuve validée. + */ +typedef struct EvidenceCopyResult EvidenceCopyResult; + +/** + * @brief Copie et vérifie un fichier de preuve. + * + * La fonction : + * + * - refuse les sources non régulières ; + * - refuse un dossier destination symbolique ; + * - crée exclusivement un nouveau fichier ; + * - copie le contenu progressivement ; + * - synchronise les données écrites ; + * - compare la taille et le SHA-256 de la source et de la destination ; + * - supprime la destination en cas d’échec après sa création. + * + * Le fichier source n’est jamais modifié. + * + * Le nom destination doit représenter uniquement un nom de fichier : + * il ne doit contenir aucun séparateur de chemin. + * + * @param source_path Chemin du fichier source. + * @param destination_directory Dossier recevant la copie. + * @param destination_name Nom du fichier destination. + * @param cancellable Objet d’annulation facultatif. + * @param error Adresse recevant une éventuelle erreur. + * + * @return Nouveau résultat possédé par l’appelant, ou NULL. + */ +EvidenceCopyResult *evidence_copy_file( + const char *source_path, + const char *destination_directory, + const char *destination_name, + GCancellable *cancellable, + GError **error +); + +/** + * @brief Libère un résultat de copie. + * + * La copie validée présente sur le disque n’est pas supprimée. + * Cette fonction accepte NULL. + * + * @param result Résultat à libérer. + */ +void evidence_copy_result_free( + EvidenceCopyResult *result +); + +/** + * @brief Retourne le chemin complet de la copie validée. + * + * Le pointeur appartient au résultat. + * + * @return Chemin destination, ou NULL. + */ +const char *evidence_copy_result_get_destination_path( + const EvidenceCopyResult *result +); + +/** + * @brief Retourne le nom du fichier destination. + * + * Le pointeur appartient au résultat. + * + * @return Nom destination, ou NULL. + */ +const char *evidence_copy_result_get_destination_name( + const EvidenceCopyResult *result +); + +/** + * @brief Retourne le SHA-256 validé de la copie. + * + * Le pointeur appartient au résultat. + * + * @return SHA-256 sur 64 caractères, ou NULL. + */ +const char *evidence_copy_result_get_sha256( + const EvidenceCopyResult *result +); + +/** + * @brief Retourne la taille validée de la copie. + * + * @return Taille en octets, ou zéro si result vaut NULL. + */ +guint64 evidence_copy_result_get_size_bytes( + const EvidenceCopyResult *result +); + +#ifdef EVIDENCE_COPY_ENABLE_TEST_HOOKS + +/** + * @brief Crochet appelé après chaque bloc copié. + */ +typedef void (*EvidenceCopyTestBlockHook)( + guint64 copied_size_bytes, + gpointer user_data +); + +void evidence_copy_test_set_block_hook( + EvidenceCopyTestBlockHook block_hook, + gpointer user_data +); + +/** + * @brief Crochet appelé avant chaque tentative d’écriture. + */ +typedef gboolean (*EvidenceCopyTestBeforeWriteHook)( + guint64 written_size_bytes, + gpointer user_data +); + +void evidence_copy_test_set_before_write_hook( + EvidenceCopyTestBeforeWriteHook before_write_hook, + gpointer user_data +); + +/** + * @brief Crochet appelé avant la vérification cryptographique finale. + */ +typedef void (*EvidenceCopyTestBeforeVerifyHook)( + const char *destination_path, + gpointer user_data +); + +void evidence_copy_test_set_before_verify_hook( + EvidenceCopyTestBeforeVerifyHook before_verify_hook, + gpointer user_data +); + +/** + * @brief Crochet appelé avant la suppression d’une copie invalide. + * + * Retourner TRUE simule un échec de suppression. + */ +typedef gboolean (*EvidenceCopyTestCleanupHook)( + const char *destination_path, + gpointer user_data +); + +/** + * @brief Configure le crochet de nettoyage réservé aux tests. + */ +void evidence_copy_test_set_cleanup_hook( + EvidenceCopyTestCleanupHook cleanup_hook, + gpointer user_data +); + +#endif + +#endif diff --git a/labfy-investigation b/labfy-investigation index f806d19453a785483d2f61b48cef4db16888d8bb..5fe153d6c76ae67d5c5e372b56584ba7b68bfc35 100755 GIT binary patch delta 112944 zcmbq+d3=o57x&yJh9pErWFiuYSVHUxVqanjV-KaZR%$C+1c^N+1T|vXaPg?3q1vi0 zf>u>4jisU}p-QTj*y@QWL#b3r-gC~g%uV>c?;meIpLXW^J?EZ#@44rmd!PF}&)B!C z+VT^D>48-vr<>?6M*T1?4=%r|(Z}A(P!%gfS6ysspPtMJ>YpZyDn+&&e$7|qWj`a= zsCxRRSgt&XEORANusBM8&hb^ttye$!JIt@j0#(JeQvc*T*z10|GgavRwofOc!?rT7Y|UhjP^R9NR`_}^|{WhL|;SpBd3cf@4p+le@lBt%-6S;srw>&sw1)O=?$oiS zDdVS%O_)pElmt`K)VC*1eG7C(j~+i`#?)z}-<~%1jl@aQrkZBYn3Onv&z=^88TX8i zVCDF#=xRK$RV6v%wAsRQqeFR0^nMQylLs`>%KNt(%BQw!2z*0Ue$}oJZfRZ4?o|z( z3U0u^uUD-DkCZo6)wn%`&8AQd`%jwWgVEPO!%0Dtyi6t!Qwt5RA$`fz88H6oG3Kd4 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 m)gY}|Jb-n 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 diff --git a/src/core/evidence_copy.c b/src/core/evidence_copy.c new file mode 100644 index 0000000..a629604 --- /dev/null +++ b/src/core/evidence_copy.c @@ -0,0 +1,1572 @@ +/****************************************************************************** + * @file evidence_copy.c + * @brief Copie sûre et vérifiée des fichiers de preuve. + ******************************************************************************/ + +#define _POSIX_C_SOURCE 200809L + +#include "core/evidence_copy.h" +#include "core/file_hash.h" + +#include +#include +#include +#include +#include + +/** + * @brief Taille du tampon utilisé pour la copie. + */ +#define EVIDENCE_COPY_BLOCK_SIZE (64U * 1024U) + +#ifdef EVIDENCE_COPY_ENABLE_TEST_HOOKS + +static EvidenceCopyTestBlockHook + evidence_copy_test_block_hook = NULL; + +static gpointer + evidence_copy_test_block_hook_data = NULL; + +void evidence_copy_test_set_block_hook( + EvidenceCopyTestBlockHook block_hook, + gpointer user_data +) +{ + evidence_copy_test_block_hook = + block_hook; + + evidence_copy_test_block_hook_data = + user_data; +} + +static void evidence_copy_test_notify_block( + guint64 copied_size_bytes +) +{ + if (evidence_copy_test_block_hook == NULL) + { + return; + } + + evidence_copy_test_block_hook( + copied_size_bytes, + evidence_copy_test_block_hook_data + ); +} + +static EvidenceCopyTestBeforeWriteHook + evidence_copy_test_before_write_hook = NULL; + +static gpointer + evidence_copy_test_before_write_hook_data = NULL; + +void evidence_copy_test_set_before_write_hook( + EvidenceCopyTestBeforeWriteHook before_write_hook, + gpointer user_data +) +{ + evidence_copy_test_before_write_hook = + before_write_hook; + + evidence_copy_test_before_write_hook_data = + user_data; +} + +static gboolean evidence_copy_test_should_fail_write( + guint64 written_size_bytes +) +{ + if (evidence_copy_test_before_write_hook == NULL) + { + return FALSE; + } + + return evidence_copy_test_before_write_hook( + written_size_bytes, + evidence_copy_test_before_write_hook_data + ); +} + +/** + * @brief Crochet appelé avant la vérification cryptographique finale. + */ +typedef void (*EvidenceCopyTestBeforeVerifyHook)( + const char *destination_path, + gpointer user_data +); + +/** + * @brief Configure le crochet de vérification réservé aux tests. + */ +void evidence_copy_test_set_before_verify_hook( + EvidenceCopyTestBeforeVerifyHook before_verify_hook, + gpointer user_data +); + +static EvidenceCopyTestBeforeVerifyHook + evidence_copy_test_before_verify_hook = NULL; + +static gpointer + evidence_copy_test_before_verify_hook_data = NULL; + +void evidence_copy_test_set_before_verify_hook( + EvidenceCopyTestBeforeVerifyHook before_verify_hook, + gpointer user_data +) +{ + evidence_copy_test_before_verify_hook = + before_verify_hook; + + evidence_copy_test_before_verify_hook_data = + user_data; +} + +static void evidence_copy_test_notify_before_verify( + const char *destination_path +) +{ + if (evidence_copy_test_before_verify_hook == NULL) + { + return; + } + + evidence_copy_test_before_verify_hook( + destination_path, + evidence_copy_test_before_verify_hook_data + ); +} + +static EvidenceCopyTestCleanupHook + evidence_copy_test_cleanup_hook = NULL; + +static gpointer + evidence_copy_test_cleanup_hook_data = NULL; + +void evidence_copy_test_set_cleanup_hook( + EvidenceCopyTestCleanupHook cleanup_hook, + gpointer user_data +) +{ + evidence_copy_test_cleanup_hook = + cleanup_hook; + + evidence_copy_test_cleanup_hook_data = + user_data; +} + +static gboolean evidence_copy_test_should_fail_cleanup( + const char *destination_path +) +{ + if (evidence_copy_test_cleanup_hook == NULL) + { + return FALSE; + } + + return evidence_copy_test_cleanup_hook( + destination_path, + evidence_copy_test_cleanup_hook_data + ); +} + +#else + +static void evidence_copy_test_notify_block( + guint64 copied_size_bytes +) +{ + (void) copied_size_bytes; +} + +static gboolean evidence_copy_test_should_fail_write( + guint64 written_size_bytes +) +{ + (void) written_size_bytes; + + return FALSE; +} + +static void evidence_copy_test_notify_before_verify( + const char *destination_path +) +{ + (void) destination_path; +} + +static gboolean evidence_copy_test_should_fail_cleanup( + const char *destination_path +) +{ + (void) destination_path; + + return FALSE; +} + +#endif + +/** + * @brief Représentation privée du résultat d’une copie validée. + */ +struct EvidenceCopyResult +{ + char *destination_path; + char *destination_name; + char *sha256; + + guint64 size_bytes; +}; + +/** + * @brief Enregistre une erreur littérale EvidenceCopy. + */ +static void evidence_copy_set_error_literal( + GError **error, + EvidenceCopyError error_code, + const char *error_message +) +{ + if (error == NULL) + { + return; + } + + g_set_error_literal( + error, + EVIDENCE_COPY_ERROR, + error_code, + error_message + ); +} + +/** + * @brief Enregistre une erreur système EvidenceCopy. + */ +static void evidence_copy_set_system_error( + GError **error, + EvidenceCopyError error_code, + const char *context, + const char *file_path, + int system_error +) +{ + if (error == NULL) + { + return; + } + + g_set_error( + error, + EVIDENCE_COPY_ERROR, + error_code, + "%s '%s' : %s", + context, + file_path, + g_strerror(system_error) + ); +} + +/** + * @brief Vérifie si une annulation a été demandée. + */ +static gboolean evidence_copy_check_cancelled( + GCancellable *cancellable, + GError **error +) +{ + if (cancellable == NULL || + !g_cancellable_is_cancelled(cancellable)) + { + return FALSE; + } + + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_CANCELLED, + "La copie de la preuve a été annulée." + ); + + return TRUE; +} + +/** + * @brief Vérifie qu’un nom représente uniquement un fichier. + */ +static gboolean evidence_copy_destination_name_is_valid( + const char *destination_name +) +{ + if (destination_name == NULL || + destination_name[0] == '\0') + { + return FALSE; + } + + if (strcmp( + destination_name, + "." + ) == 0 || + strcmp( + destination_name, + ".." + ) == 0) + { + return FALSE; + } + + if (strchr( + destination_name, + '/' + ) != NULL || + strchr( + destination_name, + '\\' + ) != NULL) + { + return FALSE; + } + + return TRUE; +} + +/** + * @brief Traduit une erreur FileHash en erreur EvidenceCopy. + */ +static EvidenceCopyError evidence_copy_map_hash_error( + const GError *hash_error +) +{ + if (hash_error == NULL) + { + return EVIDENCE_COPY_ERROR_HASH; + } + + if (g_error_matches( + hash_error, + FILE_HASH_ERROR, + FILE_HASH_ERROR_NOT_FOUND + )) + { + return EVIDENCE_COPY_ERROR_SOURCE_NOT_FOUND; + } + + if (g_error_matches( + hash_error, + FILE_HASH_ERROR, + FILE_HASH_ERROR_NOT_REGULAR + )) + { + return EVIDENCE_COPY_ERROR_SOURCE_NOT_REGULAR; + } + + if (g_error_matches( + hash_error, + FILE_HASH_ERROR, + FILE_HASH_ERROR_CANCELLED + )) + { + return EVIDENCE_COPY_ERROR_CANCELLED; + } + + return EVIDENCE_COPY_ERROR_HASH; +} + +/** + * @brief Convertit et conserve le contexte d’une erreur FileHash. + */ +static void evidence_copy_set_hash_error( + GError **error, + const GError *hash_error +) +{ + EvidenceCopyError error_code = + evidence_copy_map_hash_error( + hash_error + ); + + if (error == NULL) + { + return; + } + + g_set_error( + error, + EVIDENCE_COPY_ERROR, + error_code, + "Impossible d’analyser le fichier source : %s", + hash_error != NULL + ? hash_error->message + : "erreur SHA-256 inconnue" + ); +} + +GQuark evidence_copy_error_quark(void) +{ + return g_quark_from_static_string( + "evidence-copy-error-quark" + ); +} + +/** + * @brief Ouvre et valide le dossier de destination. + * + * Le dernier composant du chemin ne peut pas être un lien symbolique. + * + * @return Descripteur du dossier, ou -1. + */ +static int evidence_copy_open_destination_directory( + const char *destination_directory, + GError **error +) +{ + struct stat directory_status; + + int directory_descriptor = -1; + int saved_errno = 0; + + directory_descriptor = open( + destination_directory, + O_RDONLY | + O_DIRECTORY | + O_CLOEXEC | + O_NOFOLLOW + ); + + if (directory_descriptor < 0) + { + saved_errno = errno; + + evidence_copy_set_system_error( + error, + EVIDENCE_COPY_ERROR_DESTINATION_INVALID, + "Impossible d’ouvrir le dossier de destination", + destination_directory, + saved_errno + ); + + return -1; + } + + if (fstat( + directory_descriptor, + &directory_status + ) != 0) + { + saved_errno = errno; + + evidence_copy_set_system_error( + error, + EVIDENCE_COPY_ERROR_DESTINATION_INVALID, + "Impossible d’inspecter le dossier de destination", + destination_directory, + saved_errno + ); + + close( + directory_descriptor + ); + + return -1; + } + + if (!S_ISDIR(directory_status.st_mode)) + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_DESTINATION_INVALID, + "Le chemin de destination ne désigne pas un dossier." + ); + + close( + directory_descriptor + ); + + return -1; + } + + return directory_descriptor; +} + +/** + * @brief Ouvre et valide le fichier source. + * + * @return Descripteur du fichier source, ou -1. + */ +static int evidence_copy_open_source_file( + const char *source_path, + GError **error +) +{ + struct stat source_status; + + int source_descriptor = -1; + int saved_errno = 0; + + source_descriptor = open( + source_path, + O_RDONLY | + O_CLOEXEC | + O_NOFOLLOW | + O_NONBLOCK + ); + + if (source_descriptor < 0) + { + saved_errno = errno; + + if (saved_errno == ENOENT || + saved_errno == ENOTDIR) + { + evidence_copy_set_system_error( + error, + EVIDENCE_COPY_ERROR_SOURCE_NOT_FOUND, + "Le fichier source est introuvable", + source_path, + saved_errno + ); + } + else if (saved_errno == ELOOP) + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_SOURCE_NOT_REGULAR, + "Le fichier source est un lien symbolique." + ); + } + else + { + evidence_copy_set_system_error( + error, + EVIDENCE_COPY_ERROR_OPEN_SOURCE, + "Impossible d’ouvrir le fichier source", + source_path, + saved_errno + ); + } + + return -1; + } + + if (fstat( + source_descriptor, + &source_status + ) != 0) + { + saved_errno = errno; + + evidence_copy_set_system_error( + error, + EVIDENCE_COPY_ERROR_OPEN_SOURCE, + "Impossible d’inspecter le fichier source", + source_path, + saved_errno + ); + + close( + source_descriptor + ); + + return -1; + } + + if (!S_ISREG(source_status.st_mode)) + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_SOURCE_NOT_REGULAR, + "Le chemin source ne désigne pas un fichier régulier." + ); + + close( + source_descriptor + ); + + return -1; + } + + return source_descriptor; +} + +/** + * @brief Écrit intégralement un bloc dans le fichier destination. + */ +static gboolean evidence_copy_write_all( + int destination_descriptor, + const guint8 *buffer, + gsize buffer_size, + guint64 copied_size_before_block, + const char *destination_path, + GCancellable *cancellable, + GError **error +) +{ + gsize written_size = 0; + + ssize_t current_write_size = 0; + + int saved_errno = 0; + + while (written_size < buffer_size) + { + if (evidence_copy_check_cancelled( + cancellable, + error + )) + { + return FALSE; + } + + if (evidence_copy_test_should_fail_write( + copied_size_before_block + + (guint64) written_size + )) + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_WRITE, + "Une erreur d’écriture simulée est survenue." + ); + + return FALSE; + } + + current_write_size = write( + destination_descriptor, + buffer + written_size, + buffer_size - written_size + ); + + if (current_write_size < 0) + { + saved_errno = errno; + + if (saved_errno == EINTR) + { + continue; + } + + evidence_copy_set_system_error( + error, + EVIDENCE_COPY_ERROR_WRITE, + "Impossible d’écrire dans le fichier destination", + destination_path, + saved_errno + ); + + return FALSE; + } + + if (current_write_size == 0) + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_WRITE, + "L’écriture du fichier destination n’a écrit aucun octet." + ); + + return FALSE; + } + + written_size += + (gsize) current_write_size; + } + + return TRUE; +} + +/** + * @brief Copie progressivement le contenu du fichier source. + */ +static gboolean evidence_copy_contents( + int source_descriptor, + int destination_descriptor, + const char *source_path, + const char *destination_path, + GCancellable *cancellable, + guint64 *out_copied_size_bytes, + GError **error +) +{ + guint8 *buffer = NULL; + + guint64 copied_size_bytes = 0; + + ssize_t read_size = 0; + + int saved_errno = 0; + + if (out_copied_size_bytes == NULL) + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_INVALID_ARGUMENT, + "La destination de la taille copiée est invalide." + ); + + return FALSE; + } + + *out_copied_size_bytes = 0; + + buffer = g_try_malloc( + EVIDENCE_COPY_BLOCK_SIZE + ); + + if (buffer == NULL) + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_MEMORY, + "Impossible d’allouer le tampon de copie." + ); + + return FALSE; + } + + while (TRUE) + { + if (evidence_copy_check_cancelled( + cancellable, + error + )) + { + g_free( + buffer + ); + + return FALSE; + } + + read_size = read( + source_descriptor, + buffer, + EVIDENCE_COPY_BLOCK_SIZE + ); + + if (read_size < 0) + { + saved_errno = errno; + + if (saved_errno == EINTR) + { + continue; + } + + evidence_copy_set_system_error( + error, + EVIDENCE_COPY_ERROR_READ, + "Impossible de lire le fichier source", + source_path, + saved_errno + ); + + g_free( + buffer + ); + + return FALSE; + } + + if (read_size == 0) + { + break; + } + + if (!evidence_copy_write_all( + destination_descriptor, + buffer, + (gsize) read_size, + copied_size_bytes, + destination_path, + cancellable, + error + )) + { + g_free( + buffer + ); + + return FALSE; + } + + copied_size_bytes += + (guint64) read_size; + + evidence_copy_test_notify_block( + copied_size_bytes + ); + + if (evidence_copy_check_cancelled( + cancellable, + error + )) + { + g_free( + buffer + ); + + return FALSE; + } + } + + g_free( + buffer + ); + + *out_copied_size_bytes = + copied_size_bytes; + + return TRUE; +} + +/** + * @brief Crée exclusivement le fichier destination. + * + * Le fichier ne peut pas remplacer un élément existant. + * + * @return Descripteur du fichier créé, ou -1. + */ +static int evidence_copy_create_destination_file( + int destination_directory_descriptor, + const char *destination_name, + const char *destination_path, + GError **error +) +{ + int destination_descriptor = -1; + int saved_errno = 0; + + destination_descriptor = openat( + destination_directory_descriptor, + destination_name, + O_WRONLY | + O_CREAT | + O_EXCL | + O_CLOEXEC | + O_NOFOLLOW, + 0600 + ); + + if (destination_descriptor >= 0) + { + return destination_descriptor; + } + + saved_errno = errno; + + if (saved_errno == EEXIST) + { + evidence_copy_set_system_error( + error, + EVIDENCE_COPY_ERROR_DESTINATION_EXISTS, + "Le fichier destination existe déjà", + destination_path, + saved_errno + ); + } + else + { + evidence_copy_set_system_error( + error, + EVIDENCE_COPY_ERROR_CREATE_DESTINATION, + "Impossible de créer le fichier destination", + destination_path, + saved_errno + ); + } + + return -1; +} + +/** + * @brief Duplique une chaîne en signalant proprement une erreur mémoire. + */ +static char *evidence_copy_duplicate_string( + const char *value, + GError **error +) +{ + char *copy = NULL; + gsize value_size = 0; + + if (value == NULL) + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_INVALID_ARGUMENT, + "La chaîne à dupliquer est invalide." + ); + + return NULL; + } + + value_size = + strlen( + value + ); + + copy = g_try_malloc( + value_size + 1U + ); + + if (copy == NULL) + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_MEMORY, + "Impossible d’allouer une chaîne du résultat de copie." + ); + + return NULL; + } + + memcpy( + copy, + value, + value_size + 1U + ); + + return copy; +} + +/** + * @brief Signale qu’un fichier incomplet n’a pas pu être supprimé. + */ +static void evidence_copy_report_cleanup_failure( + GError **error, + const char *destination_path, + int system_error +) +{ + char *primary_message = NULL; + + if (error == NULL) + { + g_warning( + "Impossible de supprimer la copie incomplète '%s' : %s", + destination_path, + g_strerror(system_error) + ); + + return; + } + + if (*error != NULL) + { + primary_message = + g_strdup( + (*error)->message + ); + + g_clear_error( + error + ); + } + + g_set_error( + error, + EVIDENCE_COPY_ERROR, + EVIDENCE_COPY_ERROR_CLEANUP, + "Un fichier incomplet peut subsister à l’emplacement '%s' : %s. " + "Cause initiale : %s", + destination_path, + g_strerror(system_error), + primary_message != NULL + ? primary_message + : "erreur inconnue" + ); + + g_free( + primary_message + ); +} + +/** + * @brief Supprime une destination invalide. + * + * @return 0 en cas de succès, sinon -1 avec errno renseigné. + */ +static int evidence_copy_remove_invalid_destination( + int destination_directory_descriptor, + const char *destination_name, + const char *destination_path +) +{ + if (evidence_copy_test_should_fail_cleanup( + destination_path + )) + { + errno = EACCES; + + return -1; + } + + return unlinkat( + destination_directory_descriptor, + destination_name, + 0 + ); +} + +EvidenceCopyResult *evidence_copy_file( + const char *source_path, + const char *destination_directory, + const char *destination_name, + GCancellable *cancellable, + GError **error +) +{ + EvidenceCopyResult *result = NULL; + + GError *hash_error = NULL; + + char *source_sha256_before = NULL; + char *source_sha256_after = NULL; + char *destination_sha256 = NULL; + + char *destination_path = NULL; + char *destination_name_copy = NULL; + + guint64 source_size_before = 0; + guint64 source_size_after = 0; + guint64 destination_size = 0; + guint64 copied_size_bytes = 0; + + int source_descriptor = -1; + int destination_directory_descriptor = -1; + int destination_descriptor = -1; + int cleanup_errno = 0; + + gboolean destination_created = FALSE; + gboolean success = FALSE; + + g_return_val_if_fail( + error == NULL || *error == NULL, + NULL + ); + + if (source_path == NULL || + source_path[0] == '\0') + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_INVALID_ARGUMENT, + "Le chemin du fichier source est invalide." + ); + + return NULL; + } + + if (destination_directory == NULL || + destination_directory[0] == '\0') + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_INVALID_ARGUMENT, + "Le dossier de destination est invalide." + ); + + return NULL; + } + + if (!evidence_copy_destination_name_is_valid( + destination_name + )) + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_INVALID_ARGUMENT, + "Le nom du fichier destination est invalide." + ); + + return NULL; + } + + if (evidence_copy_check_cancelled( + cancellable, + error + )) + { + return NULL; + } + + /* + * Première photographie cryptographique du fichier source. + */ + if (!file_hash_compute_sha256( + source_path, + cancellable, + &source_sha256_before, + &source_size_before, + &hash_error + )) + { + evidence_copy_set_hash_error( + error, + hash_error + ); + + g_clear_error( + &hash_error + ); + + return NULL; + } + + destination_path = + g_build_filename( + destination_directory, + destination_name, + NULL + ); + + if (destination_path == NULL) + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_MEMORY, + "Impossible de construire le chemin de destination." + ); + + goto cleanup; + } + + source_descriptor = + evidence_copy_open_source_file( + source_path, + error + ); + + if (source_descriptor < 0) + { + goto cleanup; + } + + destination_directory_descriptor = + evidence_copy_open_destination_directory( + destination_directory, + error + ); + + if (destination_directory_descriptor < 0) + { + goto cleanup; + } + + if (evidence_copy_check_cancelled( + cancellable, + error + )) + { + goto cleanup; + } + + destination_descriptor = + evidence_copy_create_destination_file( + destination_directory_descriptor, + destination_name, + destination_path, + error + ); + + if (destination_descriptor < 0) + { + goto cleanup; + } + + destination_created = TRUE; + + if (!evidence_copy_contents( + source_descriptor, + destination_descriptor, + source_path, + destination_path, + cancellable, + &copied_size_bytes, + error + )) + { + goto cleanup; + } + + if (evidence_copy_check_cancelled( + cancellable, + error + )) + { + goto cleanup; + } + + if (fsync( + destination_descriptor + ) != 0) + { + evidence_copy_set_system_error( + error, + EVIDENCE_COPY_ERROR_SYNC, + "Impossible de synchroniser le fichier destination", + destination_path, + errno + ); + + goto cleanup; + } + + /* + * Un échec de fermeture d’un fichier écrit est considéré comme + * un échec de finalisation. + */ + if (close( + destination_descriptor + ) != 0) + { + destination_descriptor = -1; + + evidence_copy_set_system_error( + error, + EVIDENCE_COPY_ERROR_SYNC, + "Impossible de fermer le fichier destination", + destination_path, + errno + ); + + goto cleanup; + } + + destination_descriptor = -1; + + if (close( + source_descriptor + ) != 0) + { + g_warning( + "Impossible de fermer proprement le fichier source '%s' : %s", + source_path, + g_strerror(errno) + ); + } + + source_descriptor = -1; + + if (evidence_copy_check_cancelled( + cancellable, + error + )) + { + goto cleanup; + } + + evidence_copy_test_notify_before_verify( + destination_path + ); + + /* + * Vérification cryptographique de la copie. + */ + if (!file_hash_compute_sha256( + destination_path, + cancellable, + &destination_sha256, + &destination_size, + &hash_error + )) + { + if (error != NULL) + { + g_set_error( + error, + EVIDENCE_COPY_ERROR, + EVIDENCE_COPY_ERROR_HASH, + "Impossible de vérifier le fichier destination : %s", + hash_error != NULL + ? hash_error->message + : "erreur SHA-256 inconnue" + ); + } + + g_clear_error( + &hash_error + ); + + goto cleanup; + } + + if (evidence_copy_check_cancelled( + cancellable, + error + )) + { + goto cleanup; + } + + /* + * Deuxième photographie du source afin de détecter une modification + * survenue pendant la copie. + */ + if (!file_hash_compute_sha256( + source_path, + cancellable, + &source_sha256_after, + &source_size_after, + &hash_error + )) + { + evidence_copy_set_hash_error( + error, + hash_error + ); + + g_clear_error( + &hash_error + ); + + goto cleanup; + } + + if (copied_size_bytes != source_size_before || + destination_size != source_size_before || + source_size_after != source_size_before || + strcmp( + destination_sha256, + source_sha256_before + ) != 0 || + strcmp( + source_sha256_after, + source_sha256_before + ) != 0) + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_VERIFY, + "La source ou sa copie a changé pendant l’opération." + ); + + goto cleanup; + } + + destination_name_copy = + evidence_copy_duplicate_string( + destination_name, + error + ); + + if (destination_name_copy == NULL) + { + goto cleanup; + } + + result = + g_try_new0( + EvidenceCopyResult, + 1 + ); + + if (result == NULL) + { + evidence_copy_set_error_literal( + error, + EVIDENCE_COPY_ERROR_MEMORY, + "Impossible d’allouer le résultat de la copie." + ); + + goto cleanup; + } + + result->destination_path = + destination_path; + + destination_path = NULL; + + result->destination_name = + destination_name_copy; + + destination_name_copy = NULL; + + result->sha256 = + destination_sha256; + + destination_sha256 = NULL; + + result->size_bytes = + destination_size; + + success = TRUE; + +cleanup: + + if (destination_descriptor >= 0) + { + if (close( + destination_descriptor + ) != 0) + { + g_warning( + "Impossible de fermer le fichier destination '%s' : %s", + destination_path != NULL + ? destination_path + : destination_name, + g_strerror(errno) + ); + } + } + + if (source_descriptor >= 0) + { + if (close( + source_descriptor + ) != 0) + { + g_warning( + "Impossible de fermer le fichier source '%s' : %s", + source_path, + g_strerror(errno) + ); + } + } + + /* + * Une destination n’est conservée qu’après validation complète. + */ + if (!success && + destination_created && + destination_directory_descriptor >= 0) + { + if (evidence_copy_remove_invalid_destination( + destination_directory_descriptor, + destination_name, + destination_path != NULL + ? destination_path + : destination_name + ) != 0) + { + cleanup_errno = errno; + + evidence_copy_report_cleanup_failure( + error, + destination_path != NULL + ? destination_path + : destination_name, + cleanup_errno + ); + } + } + + if (destination_directory_descriptor >= 0) + { + if (close( + destination_directory_descriptor + ) != 0) + { + g_warning( + "Impossible de fermer le dossier destination '%s' : %s", + destination_directory, + g_strerror(errno) + ); + } + } + + g_free( + destination_name_copy + ); + + g_free( + destination_path + ); + + g_free( + destination_sha256 + ); + + g_free( + source_sha256_after + ); + + g_free( + source_sha256_before + ); + + if (!success) + { + evidence_copy_result_free( + result + ); + + result = NULL; + } + + return result; +} + +void evidence_copy_result_free( + EvidenceCopyResult *result +) +{ + if (result == NULL) + { + return; + } + + g_free( + result->sha256 + ); + + g_free( + result->destination_name + ); + + g_free( + result->destination_path + ); + + g_free( + result + ); +} + +const char *evidence_copy_result_get_destination_path( + const EvidenceCopyResult *result +) +{ + if (result == NULL) + { + return NULL; + } + + return result->destination_path; +} + +const char *evidence_copy_result_get_destination_name( + const EvidenceCopyResult *result +) +{ + if (result == NULL) + { + return NULL; + } + + return result->destination_name; +} + +const char *evidence_copy_result_get_sha256( + const EvidenceCopyResult *result +) +{ + if (result == NULL) + { + return NULL; + } + + return result->sha256; +} + +guint64 evidence_copy_result_get_size_bytes( + const EvidenceCopyResult *result +) +{ + if (result == NULL) + { + return 0; + } + + return result->size_bytes; +} diff --git a/tests/test_evidence_copy b/tests/test_evidence_copy new file mode 100755 index 0000000000000000000000000000000000000000..402f688844ce3135732f9edb0a04c5c975063e3b GIT binary patch literal 78264 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 +#include +#include +#include + +#include +#include +#include + +/** + * @brief Environnement temporaire des tests EvidenceCopy. + */ +typedef struct +{ + char *root_directory; + char *source_directory; + char *destination_directory; +} TestEvidenceCopyFixture; + +/** + * @brief Contexte d’annulation pendant la copie. + */ +typedef struct +{ + GCancellable *cancellable; + guint block_count; +} TestEvidenceCopyCancellationContext; + +/** + * @brief Contexte d’une erreur d’écriture simulée. + */ +typedef struct +{ + guint64 fail_after_size_bytes; + guint call_count; +} TestEvidenceCopyWriteFailureContext; + +/** + * @brief Contexte de corruption avant vérification. + */ +typedef struct +{ + guint call_count; +} TestEvidenceCopyVerifyFailureContext; + +/** + * @brief Contexte de modification du fichier source. + */ +typedef struct +{ + const char *source_path; + guint call_count; +} TestEvidenceCopySourceModificationContext; + +/** + * @brief Contexte d’un échec de nettoyage simulé. + */ +typedef struct +{ + guint call_count; +} TestEvidenceCopyCleanupFailureContext; + +/** + * @brief Crée un environnement temporaire isolé. + */ +static TestEvidenceCopyFixture +test_evidence_copy_fixture_create(void) +{ + TestEvidenceCopyFixture fixture = {0}; + + GError *error = NULL; + + fixture.root_directory = + g_dir_make_tmp( + "labfy-evidence-copy-test-XXXXXX", + &error + ); + + assert(error == NULL); + assert(fixture.root_directory != NULL); + + fixture.source_directory = + g_build_filename( + fixture.root_directory, + "source", + NULL + ); + + fixture.destination_directory = + g_build_filename( + fixture.root_directory, + "destination", + NULL + ); + + assert(fixture.source_directory != NULL); + assert(fixture.destination_directory != NULL); + + assert( + g_mkdir( + fixture.source_directory, + 0700 + ) == 0 + ); + + assert( + g_mkdir( + fixture.destination_directory, + 0700 + ) == 0 + ); + + return fixture; +} + +/** + * @brief Vérifie une erreur EvidenceCopy. + */ +static void test_evidence_copy_assert_error( + const GError *error, + EvidenceCopyError expected_error +) +{ + assert(error != NULL); + assert(error->domain == EVIDENCE_COPY_ERROR); + + assert( + error->code == + (gint) expected_error + ); + + assert(error->message != NULL); + assert(error->message[0] != '\0'); +} + +/** + * @brief Supprime un environnement temporaire vide. + */ +static void test_evidence_copy_fixture_clear( + TestEvidenceCopyFixture *fixture +) +{ + assert(fixture != NULL); + assert(fixture->root_directory != NULL); + assert(fixture->source_directory != NULL); + assert(fixture->destination_directory != NULL); + + assert( + g_rmdir( + fixture->destination_directory + ) == 0 + ); + + assert( + g_rmdir( + fixture->source_directory + ) == 0 + ); + + assert( + g_rmdir( + fixture->root_directory + ) == 0 + ); + + g_free( + fixture->destination_directory + ); + + g_free( + fixture->source_directory + ); + + g_free( + fixture->root_directory + ); + + fixture->destination_directory = NULL; + fixture->source_directory = NULL; + fixture->root_directory = NULL; +} + +/** + * @brief Construit un chemin dans le dossier source. + */ +static char *test_evidence_copy_build_source_path( + const TestEvidenceCopyFixture *fixture, + const char *file_name +) +{ + assert(fixture != NULL); + assert(fixture->source_directory != NULL); + assert(file_name != NULL); + + return g_build_filename( + fixture->source_directory, + file_name, + NULL + ); +} + +/** + * @brief Construit un chemin dans le dossier destination. + */ +static char *test_evidence_copy_build_destination_path( + const TestEvidenceCopyFixture *fixture, + const char *file_name +) +{ + assert(fixture != NULL); + assert(fixture->destination_directory != NULL); + assert(file_name != NULL); + + return g_build_filename( + fixture->destination_directory, + file_name, + NULL + ); +} + +/** + * @brief Vérifie les accesseurs avec un résultat NULL. + */ +static void test_evidence_copy_null_result(void) +{ + assert( + evidence_copy_result_get_destination_path( + NULL + ) == NULL + ); + + assert( + evidence_copy_result_get_destination_name( + NULL + ) == NULL + ); + + assert( + evidence_copy_result_get_sha256( + NULL + ) == NULL + ); + + assert( + evidence_copy_result_get_size_bytes( + NULL + ) == 0 + ); + + evidence_copy_result_free( + NULL + ); +} + +/** + * @brief Vérifie la copie complète du contenu connu « abc ». + */ +static void test_evidence_copy_text_file(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *result = NULL; + + char *source_path = NULL; + char *destination_path = NULL; + char *destination_name = NULL; + + char *source_contents = NULL; + char *destination_contents = NULL; + + gsize source_contents_size = 0; + gsize destination_contents_size = 0; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "original.txt" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "copie.txt" + ); + + destination_name = + g_strdup( + "copie.txt" + ); + + assert(source_path != NULL); + assert(destination_path != NULL); + assert(destination_name != NULL); + + assert( + g_file_set_contents( + source_path, + "abc", + 3, + &error + ) + ); + + assert(error == NULL); + + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + destination_name, + NULL, + &error + ); + + assert(error == NULL); + assert(result != NULL); + + /* + * La chaîne fournie par l’appelant peut être libérée : + * le résultat doit posséder sa propre copie. + */ + g_free( + destination_name + ); + + destination_name = NULL; + + assert( + strcmp( + evidence_copy_result_get_destination_path( + result + ), + destination_path + ) == 0 + ); + + assert( + strcmp( + evidence_copy_result_get_destination_name( + result + ), + "copie.txt" + ) == 0 + ); + + assert( + strcmp( + evidence_copy_result_get_sha256( + result + ), + "ba7816bf8f01cfea414140de5dae2223" + "b00361a396177a9cb410ff61f20015ad" + ) == 0 + ); + + assert( + evidence_copy_result_get_size_bytes( + result + ) == 3 + ); + + /* + * Libérer le résultat ne doit pas supprimer la copie validée. + */ + evidence_copy_result_free( + result + ); + + result = NULL; + + assert( + g_file_test( + destination_path, + G_FILE_TEST_IS_REGULAR + ) + ); + + assert( + g_file_get_contents( + source_path, + &source_contents, + &source_contents_size, + &error + ) + ); + + assert(error == NULL); + + assert( + g_file_get_contents( + destination_path, + &destination_contents, + &destination_contents_size, + &error + ) + ); + + assert(error == NULL); + + assert(source_contents_size == 3); + assert(destination_contents_size == 3); + + assert( + memcmp( + source_contents, + destination_contents, + 3 + ) == 0 + ); + + assert( + memcmp( + source_contents, + "abc", + 3 + ) == 0 + ); + + g_free( + destination_contents + ); + + g_free( + source_contents + ); + + assert( + g_remove( + destination_path + ) == 0 + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie la copie d’un fichier vide. + */ +static void test_evidence_copy_empty_file(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *result = NULL; + + char *source_path = NULL; + char *destination_path = NULL; + char *destination_contents = NULL; + + gsize destination_contents_size = 42; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "empty.bin" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "empty-copy.bin" + ); + + assert(source_path != NULL); + assert(destination_path != NULL); + + assert( + g_file_set_contents( + source_path, + "", + 0, + &error + ) + ); + + assert(error == NULL); + + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + "empty-copy.bin", + NULL, + &error + ); + + assert(error == NULL); + assert(result != NULL); + + assert( + evidence_copy_result_get_size_bytes( + result + ) == 0 + ); + + assert( + strcmp( + evidence_copy_result_get_sha256( + result + ), + "e3b0c44298fc1c149afbf4c8996fb924" + "27ae41e4649b934ca495991b7852b855" + ) == 0 + ); + + assert( + strcmp( + evidence_copy_result_get_destination_path( + result + ), + destination_path + ) == 0 + ); + + evidence_copy_result_free( + result + ); + + result = NULL; + + assert( + g_file_test( + destination_path, + G_FILE_TEST_IS_REGULAR + ) + ); + + assert( + g_file_get_contents( + destination_path, + &destination_contents, + &destination_contents_size, + &error + ) + ); + + assert(error == NULL); + assert(destination_contents != NULL); + assert(destination_contents_size == 0); + + g_free( + destination_contents + ); + + assert( + g_remove( + destination_path + ) == 0 + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie la copie exacte de données binaires. + */ +static void test_evidence_copy_binary_file(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + static const guint8 binary_data[] = + { + 0x00, + 0xFF, + 0x80, + 0x41, + 0x00, + 0x7F, + 0x10 + }; + + EvidenceCopyResult *result = NULL; + + char *source_path = NULL; + char *destination_path = NULL; + char *destination_contents = NULL; + + gsize destination_contents_size = 0; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "binary-source.bin" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "binary-copy.bin" + ); + + assert(source_path != NULL); + assert(destination_path != NULL); + + assert( + g_file_set_contents( + source_path, + (const char *) binary_data, + (gssize) sizeof(binary_data), + &error + ) + ); + + assert(error == NULL); + + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + "binary-copy.bin", + NULL, + &error + ); + + assert(error == NULL); + assert(result != NULL); + + assert( + evidence_copy_result_get_size_bytes( + result + ) == sizeof(binary_data) + ); + + assert( + strcmp( + evidence_copy_result_get_sha256( + result + ), + "c90d3a7754f84abc867e780e5a0c0f8d" + "a5c663bd1766ad89e538536a3763f367" + ) == 0 + ); + + evidence_copy_result_free( + result + ); + + assert( + g_file_get_contents( + destination_path, + &destination_contents, + &destination_contents_size, + &error + ) + ); + + assert(error == NULL); + + assert( + destination_contents_size == + sizeof(binary_data) + ); + + assert( + memcmp( + destination_contents, + binary_data, + sizeof(binary_data) + ) == 0 + ); + + g_free( + destination_contents + ); + + assert( + g_remove( + destination_path + ) == 0 + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie la copie d’un fichier supérieur au tampon. + */ +static void test_evidence_copy_multiple_blocks(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + const gsize data_size = + (200U * 1024U) + 123U; + + EvidenceCopyResult *result = NULL; + + guint8 *source_data = NULL; + + char *source_path = NULL; + char *destination_path = NULL; + char *destination_contents = NULL; + + gsize destination_contents_size = 0; + gsize data_index = 0; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "large-source.bin" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "large-copy.bin" + ); + + assert(source_path != NULL); + assert(destination_path != NULL); + + source_data = + g_malloc( + data_size + ); + + assert(source_data != NULL); + + for (data_index = 0; + data_index < data_size; + data_index++) + { + source_data[data_index] = + (guint8) (data_index % 251U); + } + + assert( + g_file_set_contents( + source_path, + (const char *) source_data, + (gssize) data_size, + &error + ) + ); + + assert(error == NULL); + + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + "large-copy.bin", + NULL, + &error + ); + + assert(error == NULL); + assert(result != NULL); + + assert( + evidence_copy_result_get_size_bytes( + result + ) == data_size + ); + + assert( + strcmp( + evidence_copy_result_get_sha256( + result + ), + "bc5ad58e926b1f79d9840418910f47ba" + "1e947fb137170b8d5403a537b888c4af" + ) == 0 + ); + + evidence_copy_result_free( + result + ); + + assert( + g_file_get_contents( + destination_path, + &destination_contents, + &destination_contents_size, + &error + ) + ); + + assert(error == NULL); + assert(destination_contents_size == data_size); + + assert( + memcmp( + destination_contents, + source_data, + data_size + ) == 0 + ); + + g_free( + destination_contents + ); + + g_free( + source_data + ); + + assert( + g_remove( + destination_path + ) == 0 + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie les permissions restrictives de la copie. + */ +static void test_evidence_copy_permissions(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *result = NULL; + + struct stat destination_status; + + char *source_path = NULL; + char *destination_path = NULL; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "permissions-source.bin" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "permissions-copy.bin" + ); + + assert(source_path != NULL); + assert(destination_path != NULL); + + assert( + g_file_set_contents( + source_path, + "preuve", + 6, + &error + ) + ); + + assert(error == NULL); + + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + "permissions-copy.bin", + NULL, + &error + ); + + assert(error == NULL); + assert(result != NULL); + + assert( + stat( + destination_path, + &destination_status + ) == 0 + ); + + assert( + S_ISREG( + destination_status.st_mode + ) + ); + + /* + * Aucun droit pour le groupe ou les autres utilisateurs. + */ + assert( + (destination_status.st_mode & 0077) == 0 + ); + + evidence_copy_result_free( + result + ); + + assert( + g_remove( + destination_path + ) == 0 + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie qu’un fichier existant n’est jamais écrasé. + */ +static void test_evidence_copy_destination_exists(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *result = NULL; + + char *source_path = NULL; + char *destination_path = NULL; + + char *source_contents = NULL; + char *destination_contents = NULL; + + gsize source_contents_size = 0; + gsize destination_contents_size = 0; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "existing-source.bin" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "existing-copy.bin" + ); + + assert(source_path != NULL); + assert(destination_path != NULL); + + assert( + g_file_set_contents( + source_path, + "nouvelle preuve", + 15, + &error + ) + ); + + assert(error == NULL); + + assert( + g_file_set_contents( + destination_path, + "ne pas modifier", + 15, + &error + ) + ); + + assert(error == NULL); + + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + "existing-copy.bin", + NULL, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_DESTINATION_EXISTS + ); + + g_clear_error( + &error + ); + + assert( + g_file_get_contents( + source_path, + &source_contents, + &source_contents_size, + &error + ) + ); + + assert(error == NULL); + + assert( + g_file_get_contents( + destination_path, + &destination_contents, + &destination_contents_size, + &error + ) + ); + + assert(error == NULL); + + assert(source_contents_size == 15); + assert(destination_contents_size == 15); + + assert( + memcmp( + source_contents, + "nouvelle preuve", + 15 + ) == 0 + ); + + assert( + memcmp( + destination_contents, + "ne pas modifier", + 15 + ) == 0 + ); + + g_free( + destination_contents + ); + + g_free( + source_contents + ); + + assert( + g_remove( + destination_path + ) == 0 + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie qu’aucun fichier destination n’a été créé. + */ +static void test_evidence_copy_assert_destination_absent( + const char *destination_path +) +{ + assert(destination_path != NULL); + + assert( + !g_file_test( + destination_path, + G_FILE_TEST_EXISTS + ) + ); +} + +/** + * @brief Vérifie le refus des paramètres obligatoires invalides. + */ +static void test_evidence_copy_invalid_arguments(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *result = NULL; + + GError *error = NULL; + + result = + evidence_copy_file( + NULL, + fixture.destination_directory, + "copy.bin", + NULL, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_INVALID_ARGUMENT + ); + + g_clear_error( + &error + ); + + result = + evidence_copy_file( + "", + fixture.destination_directory, + "copy.bin", + NULL, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_INVALID_ARGUMENT + ); + + g_clear_error( + &error + ); + + result = + evidence_copy_file( + "/tmp/source.bin", + NULL, + "copy.bin", + NULL, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_INVALID_ARGUMENT + ); + + g_clear_error( + &error + ); + + result = + evidence_copy_file( + "/tmp/source.bin", + "", + "copy.bin", + NULL, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_INVALID_ARGUMENT + ); + + g_clear_error( + &error + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie le refus des noms pouvant représenter un chemin. + */ +static void test_evidence_copy_invalid_destination_names(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + static const char *invalid_names[] = + { + NULL, + "", + ".", + "..", + "subdirectory/copy.bin", + "subdirectory\\copy.bin" + }; + + EvidenceCopyResult *result = NULL; + + char *source_path = NULL; + + gsize name_index = 0; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "valid-source.bin" + ); + + assert(source_path != NULL); + + assert( + g_file_set_contents( + source_path, + "source", + 6, + &error + ) + ); + + assert(error == NULL); + + for (name_index = 0; + name_index < G_N_ELEMENTS(invalid_names); + name_index++) + { + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + invalid_names[name_index], + NULL, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_INVALID_ARGUMENT + ); + + g_clear_error( + &error + ); + } + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie le refus d’un fichier source absent. + */ +static void test_evidence_copy_missing_source(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *result = NULL; + + char *source_path = NULL; + char *destination_path = NULL; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "missing.bin" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "copy.bin" + ); + + assert(source_path != NULL); + assert(destination_path != NULL); + + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + "copy.bin", + NULL, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_SOURCE_NOT_FOUND + ); + + g_clear_error( + &error + ); + + test_evidence_copy_assert_destination_absent( + destination_path + ); + + g_free( + destination_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie qu’un dossier ne peut pas devenir une preuve. + */ +static void test_evidence_copy_source_directory(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *result = NULL; + + char *destination_path = NULL; + + GError *error = NULL; + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "copy.bin" + ); + + assert(destination_path != NULL); + + result = + evidence_copy_file( + fixture.source_directory, + fixture.destination_directory, + "copy.bin", + NULL, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_SOURCE_NOT_REGULAR + ); + + g_clear_error( + &error + ); + + test_evidence_copy_assert_destination_absent( + destination_path + ); + + g_free( + destination_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie qu’un lien symbolique source n’est jamais suivi. + */ +static void test_evidence_copy_source_symbolic_link(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *result = NULL; + + char *target_path = NULL; + char *link_path = NULL; + char *destination_path = NULL; + + GError *error = NULL; + + target_path = + test_evidence_copy_build_source_path( + &fixture, + "target.bin" + ); + + link_path = + test_evidence_copy_build_source_path( + &fixture, + "source-link.bin" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "copy.bin" + ); + + assert(target_path != NULL); + assert(link_path != NULL); + assert(destination_path != NULL); + + assert( + g_file_set_contents( + target_path, + "secret", + 6, + &error + ) + ); + + assert(error == NULL); + + assert( + symlink( + target_path, + link_path + ) == 0 + ); + + result = + evidence_copy_file( + link_path, + fixture.destination_directory, + "copy.bin", + NULL, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_SOURCE_NOT_REGULAR + ); + + g_clear_error( + &error + ); + + test_evidence_copy_assert_destination_absent( + destination_path + ); + + assert( + g_remove( + link_path + ) == 0 + ); + + assert( + g_remove( + target_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + link_path + ); + + g_free( + target_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie qu’un tube nommé est refusé sans blocage. + */ +static void test_evidence_copy_source_named_pipe(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *result = NULL; + + char *pipe_path = NULL; + char *destination_path = NULL; + + GError *error = NULL; + + pipe_path = + test_evidence_copy_build_source_path( + &fixture, + "source.fifo" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "copy.bin" + ); + + assert(pipe_path != NULL); + assert(destination_path != NULL); + + assert( + mkfifo( + pipe_path, + 0600 + ) == 0 + ); + + result = + evidence_copy_file( + pipe_path, + fixture.destination_directory, + "copy.bin", + NULL, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_SOURCE_NOT_REGULAR + ); + + g_clear_error( + &error + ); + + test_evidence_copy_assert_destination_absent( + destination_path + ); + + assert( + g_remove( + pipe_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + pipe_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie une annulation demandée avant l’import. + */ +static void test_evidence_copy_cancelled_before_start(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *result = NULL; + + GCancellable *cancellable = NULL; + + char *source_path = NULL; + char *destination_path = NULL; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "cancelled-source.bin" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "cancelled-copy.bin" + ); + + assert(source_path != NULL); + assert(destination_path != NULL); + + assert( + g_file_set_contents( + source_path, + "source stable", + 13, + &error + ) + ); + + assert(error == NULL); + + cancellable = + g_cancellable_new(); + + assert(cancellable != NULL); + + g_cancellable_cancel( + cancellable + ); + + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + "cancelled-copy.bin", + cancellable, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_CANCELLED + ); + + g_clear_error( + &error + ); + + test_evidence_copy_assert_destination_absent( + destination_path + ); + + g_object_unref( + cancellable + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie le refus d’un dossier destination absent. + */ +static void test_evidence_copy_missing_destination_directory(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *result = NULL; + + char *source_path = NULL; + char *missing_directory = NULL; + char *destination_path = NULL; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "source.bin" + ); + + missing_directory = + g_build_filename( + fixture.root_directory, + "missing-destination", + NULL + ); + + destination_path = + g_build_filename( + missing_directory, + "copy.bin", + NULL + ); + + assert(source_path != NULL); + assert(missing_directory != NULL); + assert(destination_path != NULL); + + assert( + g_file_set_contents( + source_path, + "preuve", + 6, + &error + ) + ); + + assert(error == NULL); + + result = + evidence_copy_file( + source_path, + missing_directory, + "copy.bin", + NULL, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_DESTINATION_INVALID + ); + + g_clear_error( + &error + ); + + test_evidence_copy_assert_destination_absent( + destination_path + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + missing_directory + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie qu’un fichier ne peut pas servir de dossier destination. + */ +static void test_evidence_copy_destination_is_file(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *result = NULL; + + char *source_path = NULL; + char *fake_directory_path = NULL; + + char *fake_directory_contents = NULL; + gsize fake_directory_contents_size = 0; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "source.bin" + ); + + fake_directory_path = + g_build_filename( + fixture.root_directory, + "not-a-directory", + NULL + ); + + assert(source_path != NULL); + assert(fake_directory_path != NULL); + + assert( + g_file_set_contents( + source_path, + "preuve", + 6, + &error + ) + ); + + assert(error == NULL); + + assert( + g_file_set_contents( + fake_directory_path, + "contenu intact", + 14, + &error + ) + ); + + assert(error == NULL); + + result = + evidence_copy_file( + source_path, + fake_directory_path, + "copy.bin", + NULL, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_DESTINATION_INVALID + ); + + g_clear_error( + &error + ); + + /* + * Le fichier pris pour un dossier doit rester intact. + */ + assert( + g_file_get_contents( + fake_directory_path, + &fake_directory_contents, + &fake_directory_contents_size, + &error + ) + ); + + assert(error == NULL); + assert(fake_directory_contents_size == 14); + + assert( + memcmp( + fake_directory_contents, + "contenu intact", + 14 + ) == 0 + ); + + g_free( + fake_directory_contents + ); + + assert( + g_remove( + fake_directory_path + ) == 0 + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + fake_directory_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie qu’un dossier destination symbolique n’est pas suivi. + */ +static void test_evidence_copy_destination_symbolic_link(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *result = NULL; + + char *source_path = NULL; + char *link_path = NULL; + char *real_destination_path = NULL; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "source.bin" + ); + + link_path = + g_build_filename( + fixture.root_directory, + "destination-link", + NULL + ); + + real_destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "copy.bin" + ); + + assert(source_path != NULL); + assert(link_path != NULL); + assert(real_destination_path != NULL); + + assert( + g_file_set_contents( + source_path, + "preuve", + 6, + &error + ) + ); + + assert(error == NULL); + + assert( + symlink( + fixture.destination_directory, + link_path + ) == 0 + ); + + result = + evidence_copy_file( + source_path, + link_path, + "copy.bin", + NULL, + &error + ); + + assert(result == NULL); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_DESTINATION_INVALID + ); + + g_clear_error( + &error + ); + + /* + * La cible réelle du lien ne doit recevoir aucun fichier. + */ + test_evidence_copy_assert_destination_absent( + real_destination_path + ); + + assert( + g_remove( + link_path + ) == 0 + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + real_destination_path + ); + + g_free( + link_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Annule la copie après le premier bloc. + */ +static void test_evidence_copy_cancel_after_first_block( + guint64 copied_size_bytes, + gpointer user_data +) +{ + TestEvidenceCopyCancellationContext *context = + user_data; + + assert(context != NULL); + assert(context->cancellable != NULL); + assert(copied_size_bytes > 0); + + context->block_count++; + + if (context->block_count == 1) + { + g_cancellable_cancel( + context->cancellable + ); + } +} + +/** + * @brief Vérifie l’annulation pendant une copie en cours. + */ +static void test_evidence_copy_cancelled_during_copy(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + TestEvidenceCopyCancellationContext context = {0}; + + const gsize data_size = + 256U * 1024U; + + EvidenceCopyResult *result = NULL; + + guint8 *source_data = NULL; + + char *source_path = NULL; + char *destination_path = NULL; + + gsize data_index = 0; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "cancel-source.bin" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "cancel-copy.bin" + ); + + assert(source_path != NULL); + assert(destination_path != NULL); + + source_data = + g_malloc( + data_size + ); + + assert(source_data != NULL); + + for (data_index = 0; + data_index < data_size; + data_index++) + { + source_data[data_index] = + (guint8) (data_index % 251U); + } + + assert( + g_file_set_contents( + source_path, + (const char *) source_data, + (gssize) data_size, + &error + ) + ); + + assert(error == NULL); + + context.cancellable = + g_cancellable_new(); + + assert(context.cancellable != NULL); + + evidence_copy_test_set_block_hook( + test_evidence_copy_cancel_after_first_block, + &context + ); + + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + "cancel-copy.bin", + context.cancellable, + &error + ); + + /* + * Toujours retirer le crochet avant les assertions suivantes. + */ + evidence_copy_test_set_block_hook( + NULL, + NULL + ); + + assert(result == NULL); + assert(context.block_count == 1); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_CANCELLED + ); + + g_clear_error( + &error + ); + + /* + * La copie partielle doit avoir été supprimée. + */ + test_evidence_copy_assert_destination_absent( + destination_path + ); + + /* + * Le fichier source doit rester intact. + */ + assert( + g_file_test( + source_path, + G_FILE_TEST_IS_REGULAR + ) + ); + + g_object_unref( + context.cancellable + ); + + g_free( + source_data + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Déclenche une erreur après la quantité demandée. + */ +static gboolean test_evidence_copy_fail_write_after_size( + guint64 written_size_bytes, + gpointer user_data +) +{ + TestEvidenceCopyWriteFailureContext *context = + user_data; + + assert(context != NULL); + + context->call_count++; + + return written_size_bytes >= + context->fail_after_size_bytes; +} + +/** + * @brief Vérifie le nettoyage après une erreur d’écriture. + */ +static void test_evidence_copy_write_failure_cleanup(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + TestEvidenceCopyWriteFailureContext context = {0}; + + const gsize data_size = + 256U * 1024U; + + EvidenceCopyResult *result = NULL; + + guint8 *source_data = NULL; + + char *source_path = NULL; + char *destination_path = NULL; + char *source_contents = NULL; + + gsize data_index = 0; + gsize source_contents_size = 0; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "write-failure-source.bin" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "write-failure-copy.bin" + ); + + assert(source_path != NULL); + assert(destination_path != NULL); + + source_data = + g_malloc( + data_size + ); + + assert(source_data != NULL); + + for (data_index = 0; + data_index < data_size; + data_index++) + { + source_data[data_index] = + (guint8) (data_index % 251U); + } + + assert( + g_file_set_contents( + source_path, + (const char *) source_data, + (gssize) data_size, + &error + ) + ); + + assert(error == NULL); + + /* + * Le premier bloc de 64 Kio est écrit. + * L’écriture suivante doit échouer. + */ + context.fail_after_size_bytes = + 64U * 1024U; + + evidence_copy_test_set_before_write_hook( + test_evidence_copy_fail_write_after_size, + &context + ); + + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + "write-failure-copy.bin", + NULL, + &error + ); + + evidence_copy_test_set_before_write_hook( + NULL, + NULL + ); + + assert(result == NULL); + assert(context.call_count >= 2); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_WRITE + ); + + g_clear_error( + &error + ); + + /* + * Le fichier partiel ne doit plus exister. + */ + test_evidence_copy_assert_destination_absent( + destination_path + ); + + /* + * Le fichier source doit rester strictement intact. + */ + assert( + g_file_get_contents( + source_path, + &source_contents, + &source_contents_size, + &error + ) + ); + + assert(error == NULL); + assert(source_contents_size == data_size); + + assert( + memcmp( + source_contents, + source_data, + data_size + ) == 0 + ); + + g_free( + source_contents + ); + + g_free( + source_data + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Corrompt volontairement la destination avant son contrôle. + */ +static void test_evidence_copy_corrupt_before_verify( + const char *destination_path, + gpointer user_data +) +{ + TestEvidenceCopyVerifyFailureContext *context = + user_data; + + GError *error = NULL; + + assert(context != NULL); + assert(destination_path != NULL); + + context->call_count++; + + assert( + g_file_set_contents( + destination_path, + "copie corrompue", + 15, + &error + ) + ); + + assert(error == NULL); +} + +/** + * @brief Vérifie le nettoyage après une corruption de la copie. + */ +static void test_evidence_copy_verification_failure_cleanup(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + TestEvidenceCopyVerifyFailureContext context = {0}; + + EvidenceCopyResult *result = NULL; + + char *source_path = NULL; + char *destination_path = NULL; + char *source_contents = NULL; + + gsize source_contents_size = 0; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "verify-source.bin" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "verify-copy.bin" + ); + + assert(source_path != NULL); + assert(destination_path != NULL); + + assert( + g_file_set_contents( + source_path, + "preuve originale", + 16, + &error + ) + ); + + assert(error == NULL); + + evidence_copy_test_set_before_verify_hook( + test_evidence_copy_corrupt_before_verify, + &context + ); + + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + "verify-copy.bin", + NULL, + &error + ); + + evidence_copy_test_set_before_verify_hook( + NULL, + NULL + ); + + assert(result == NULL); + assert(context.call_count == 1); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_VERIFY + ); + + g_clear_error( + &error + ); + + /* + * La copie corrompue doit avoir été supprimée. + */ + test_evidence_copy_assert_destination_absent( + destination_path + ); + + /* + * La source doit être restée intacte. + */ + assert( + g_file_get_contents( + source_path, + &source_contents, + &source_contents_size, + &error + ) + ); + + assert(error == NULL); + assert(source_contents_size == 16); + + assert( + memcmp( + source_contents, + "preuve originale", + 16 + ) == 0 + ); + + g_free( + source_contents + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Modifie la source après sa copie. + */ +static void test_evidence_copy_modify_source_before_verify( + const char *destination_path, + gpointer user_data +) +{ + TestEvidenceCopySourceModificationContext *context = + user_data; + + GError *error = NULL; + + assert(destination_path != NULL); + assert(context != NULL); + assert(context->source_path != NULL); + + context->call_count++; + + assert( + g_file_set_contents( + context->source_path, + "source modifiee", + 15, + &error + ) + ); + + assert(error == NULL); +} +/** + * @brief Vérifie la détection d’une source modifiée pendant la copie. + */ +static void test_evidence_copy_source_modified_during_copy(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + TestEvidenceCopySourceModificationContext context = {0}; + + EvidenceCopyResult *result = NULL; + + char *source_path = NULL; + char *destination_path = NULL; + char *source_contents = NULL; + + gsize source_contents_size = 0; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "changing-source.bin" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "changing-copy.bin" + ); + + assert(source_path != NULL); + assert(destination_path != NULL); + + assert( + g_file_set_contents( + source_path, + "source initiale", + 15, + &error + ) + ); + + assert(error == NULL); + + context.source_path = + source_path; + + evidence_copy_test_set_before_verify_hook( + test_evidence_copy_modify_source_before_verify, + &context + ); + + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + "changing-copy.bin", + NULL, + &error + ); + + evidence_copy_test_set_before_verify_hook( + NULL, + NULL + ); + + assert(result == NULL); + assert(context.call_count == 1); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_VERIFY + ); + + g_clear_error( + &error + ); + + /* + * La destination n’est pas fiable et doit être supprimée. + */ + test_evidence_copy_assert_destination_absent( + destination_path + ); + + /* + * EvidenceCopy ne doit pas tenter de restaurer ou modifier la source. + * Elle reste donc dans l’état imposé par le test. + */ + assert( + g_file_get_contents( + source_path, + &source_contents, + &source_contents_size, + &error + ) + ); + + assert(error == NULL); + assert(source_contents_size == 15); + + assert( + memcmp( + source_contents, + "source modifiee", + 15 + ) == 0 + ); + + g_free( + source_contents + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Simule systématiquement un échec de suppression. + */ +static gboolean test_evidence_copy_fail_cleanup( + const char *destination_path, + gpointer user_data +) +{ + TestEvidenceCopyCleanupFailureContext *context = + user_data; + + assert(context != NULL); + assert(destination_path != NULL); + assert(destination_path[0] != '\0'); + + context->call_count++; + + return TRUE; +} + +/** + * @brief Vérifie le signalement d’un fichier orphelin. + */ +static void test_evidence_copy_cleanup_failure_reported(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + TestEvidenceCopyVerifyFailureContext verify_context = {0}; + TestEvidenceCopyCleanupFailureContext cleanup_context = {0}; + + EvidenceCopyResult *result = NULL; + + char *source_path = NULL; + char *destination_path = NULL; + + GError *error = NULL; + + source_path = + test_evidence_copy_build_source_path( + &fixture, + "cleanup-source.bin" + ); + + destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "cleanup-copy.bin" + ); + + assert(source_path != NULL); + assert(destination_path != NULL); + + assert( + g_file_set_contents( + source_path, + "preuve originale", + 16, + &error + ) + ); + + assert(error == NULL); + + evidence_copy_test_set_before_verify_hook( + test_evidence_copy_corrupt_before_verify, + &verify_context + ); + + evidence_copy_test_set_cleanup_hook( + test_evidence_copy_fail_cleanup, + &cleanup_context + ); + + result = + evidence_copy_file( + source_path, + fixture.destination_directory, + "cleanup-copy.bin", + NULL, + &error + ); + + /* + * Retirer les deux crochets avant toute autre opération. + */ + evidence_copy_test_set_cleanup_hook( + NULL, + NULL + ); + + evidence_copy_test_set_before_verify_hook( + NULL, + NULL + ); + + assert(result == NULL); + assert(verify_context.call_count == 1); + assert(cleanup_context.call_count == 1); + + test_evidence_copy_assert_error( + error, + EVIDENCE_COPY_ERROR_CLEANUP + ); + + /* + * Le message doit identifier le fichier potentiellement orphelin. + */ + assert( + strstr( + error->message, + destination_path + ) != NULL + ); + + /* + * La cause initiale doit rester visible. + */ + assert( + strstr( + error->message, + "Cause initiale" + ) != NULL + ); + + g_clear_error( + &error + ); + + /* + * L’échec étant simulé, le fichier doit toujours exister. + */ + assert( + g_file_test( + destination_path, + G_FILE_TEST_IS_REGULAR + ) + ); + + /* + * Le test effectue ensuite lui-même le nettoyage réel. + */ + assert( + g_remove( + destination_path + ) == 0 + ); + + assert( + g_remove( + source_path + ) == 0 + ); + + g_free( + destination_path + ); + + g_free( + source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +/** + * @brief Vérifie l’indépendance de plusieurs copies successives. + */ +static void test_evidence_copy_successive_calls(void) +{ + TestEvidenceCopyFixture fixture = + test_evidence_copy_fixture_create(); + + EvidenceCopyResult *first_result = NULL; + EvidenceCopyResult *second_result = NULL; + + char *first_source_path = NULL; + char *second_source_path = NULL; + + char *first_destination_path = NULL; + char *second_destination_path = NULL; + + GError *error = NULL; + + first_source_path = + test_evidence_copy_build_source_path( + &fixture, + "first-source.bin" + ); + + second_source_path = + test_evidence_copy_build_source_path( + &fixture, + "second-source.bin" + ); + + first_destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "first-copy.bin" + ); + + second_destination_path = + test_evidence_copy_build_destination_path( + &fixture, + "second-copy.bin" + ); + + assert(first_source_path != NULL); + assert(second_source_path != NULL); + assert(first_destination_path != NULL); + assert(second_destination_path != NULL); + + assert( + g_file_set_contents( + first_source_path, + "premiere preuve", + 15, + &error + ) + ); + + assert(error == NULL); + + assert( + g_file_set_contents( + second_source_path, + "deuxieme preuve", + 15, + &error + ) + ); + + assert(error == NULL); + + first_result = + evidence_copy_file( + first_source_path, + fixture.destination_directory, + "first-copy.bin", + NULL, + &error + ); + + assert(error == NULL); + assert(first_result != NULL); + + second_result = + evidence_copy_file( + second_source_path, + fixture.destination_directory, + "second-copy.bin", + NULL, + &error + ); + + assert(error == NULL); + assert(second_result != NULL); + + assert( + strcmp( + evidence_copy_result_get_destination_path( + first_result + ), + first_destination_path + ) == 0 + ); + + assert( + strcmp( + evidence_copy_result_get_destination_path( + second_result + ), + second_destination_path + ) == 0 + ); + + assert( + strcmp( + evidence_copy_result_get_destination_name( + first_result + ), + "first-copy.bin" + ) == 0 + ); + + assert( + strcmp( + evidence_copy_result_get_destination_name( + second_result + ), + "second-copy.bin" + ) == 0 + ); + + assert( + evidence_copy_result_get_size_bytes( + first_result + ) == 15 + ); + + assert( + evidence_copy_result_get_size_bytes( + second_result + ) == 15 + ); + + assert( + strcmp( + evidence_copy_result_get_sha256( + first_result + ), + evidence_copy_result_get_sha256( + second_result + ) + ) != 0 + ); + + assert( + g_file_test( + first_destination_path, + G_FILE_TEST_IS_REGULAR + ) + ); + + assert( + g_file_test( + second_destination_path, + G_FILE_TEST_IS_REGULAR + ) + ); + + evidence_copy_result_free( + second_result + ); + + evidence_copy_result_free( + first_result + ); + + assert( + g_remove( + second_destination_path + ) == 0 + ); + + assert( + g_remove( + first_destination_path + ) == 0 + ); + + assert( + g_remove( + second_source_path + ) == 0 + ); + + assert( + g_remove( + first_source_path + ) == 0 + ); + + g_free( + second_destination_path + ); + + g_free( + first_destination_path + ); + + g_free( + second_source_path + ); + + g_free( + first_source_path + ); + + test_evidence_copy_fixture_clear( + &fixture + ); +} + +int main(void) +{ + test_evidence_copy_null_result(); + test_evidence_copy_text_file(); + test_evidence_copy_empty_file(); + test_evidence_copy_binary_file(); + test_evidence_copy_multiple_blocks(); + test_evidence_copy_permissions(); + test_evidence_copy_destination_exists(); + test_evidence_copy_invalid_arguments(); + test_evidence_copy_invalid_destination_names(); + test_evidence_copy_missing_source(); + test_evidence_copy_source_directory(); + test_evidence_copy_source_symbolic_link(); + test_evidence_copy_source_named_pipe(); + test_evidence_copy_cancelled_before_start(); + test_evidence_copy_missing_destination_directory(); + test_evidence_copy_destination_is_file(); + test_evidence_copy_destination_symbolic_link(); + test_evidence_copy_cancelled_during_copy(); + test_evidence_copy_write_failure_cleanup(); + test_evidence_copy_verification_failure_cleanup(); + test_evidence_copy_source_modified_during_copy(); + test_evidence_copy_cleanup_failure_reported(); + test_evidence_copy_successive_calls(); + + printf( + "EvidenceCopy : premiers tests de copie valides.\n" + ); + + return 0; +}