Copier de façon sûre un fichier de preuve #48

Closed
opened 2026-07-19 13:54:24 +02:00 by fy59 · 0 comments
Owner

Copier de façon sûre un fichier de preuve

Objectif

Ajouter un module indépendant capable de copier un fichier source vers l’espace des preuves originales d’une enquête, sans écrasement, sans modification du fichier source et avec vérification cryptographique après copie.

Ce module utilisera le calcul SHA-256 déjà disponible pour garantir que la copie produite est strictement identique au fichier source.

Contexte

Le module FileHash permet désormais de calculer :

  • le SHA-256 d’un fichier régulier ;
  • sa taille exacte ;
  • avec lecture par blocs ;
  • avec prise en charge de GCancellable ;
  • sans suivre les liens symboliques.

La prochaine étape du futur import de preuves consiste à produire une copie maîtrisée dans l’enquête.

Cette copie devra être considérée comme l’original de travail conservé par Labfy Investigation. Le fichier fourni par l’utilisateur doit rester intact.

Périmètre

Créer :

include/core/evidence_copy.h
src/core/evidence_copy.c
tests/test_evidence_copy.c

Mettre à jour le Makefile afin de compiler le nouveau module et d’exécuter ses tests avec make test.

API attendue

Le module doit exposer un résultat opaque ou structuré contenant au minimum :

  • le chemin final de la copie ;
  • le nom final du fichier ;
  • la taille copiée ;
  • le SHA-256 vérifié.

Proposition d’API :

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;

#define EVIDENCE_COPY_ERROR     evidence_copy_error_quark()

GQuark evidence_copy_error_quark(void);

typedef struct EvidenceCopyResult EvidenceCopyResult;

EvidenceCopyResult *evidence_copy_file(
    const char *source_path,
    const char *destination_directory,
    const char *destination_name,
    GCancellable *cancellable,
    GError **error
);

void evidence_copy_result_free(
    EvidenceCopyResult *result
);

const char *evidence_copy_result_get_destination_path(
    const EvidenceCopyResult *result
);

const char *evidence_copy_result_get_destination_name(
    const EvidenceCopyResult *result
);

const char *evidence_copy_result_get_sha256(
    const EvidenceCopyResult *result
);

guint64 evidence_copy_result_get_size_bytes(
    const EvidenceCopyResult *result
);

L’API exacte peut être adaptée, mais le résultat retourné doit rester immuable pour l’appelant et propriétaire de ses chaînes.

Responsabilités du module

Le module doit :

  1. valider le fichier source ;
  2. valider le dossier de destination ;
  3. valider le nom de destination ;
  4. calculer le SHA-256 et la taille du fichier source ;
  5. créer exclusivement un nouveau fichier ;
  6. copier les données par blocs ;
  7. synchroniser les données écrites ;
  8. fermer le fichier de destination ;
  9. recalculer le SHA-256 et la taille de la copie ;
  10. comparer source et destination ;
  11. supprimer toute copie incomplète ou invalide en cas d’échec ;
  12. retourner un résultat uniquement après validation complète.

Hors responsabilité

Le module ne doit pas :

  • créer un EvidenceRecord ;
  • insérer une preuve dans SQLite ;
  • choisir automatiquement le sous-dossier métier ;
  • générer l’identifiant UUID ;
  • afficher une fenêtre GTK ;
  • modifier le fichier source ;
  • extraire les métadonnées du fichier ;
  • lancer une commande shell ;
  • interpréter le contenu du fichier.

Validation des paramètres

La fonction doit refuser :

  • un chemin source NULL ou vide ;
  • un dossier de destination NULL ou vide ;
  • un nom de destination NULL ou vide ;
  • un nom égal à . ou .. ;
  • un nom contenant / ;
  • un nom contenant \ ;
  • un nom possédant un composant de chemin ;
  • un GError déjà initialisé.

Le nom fourni doit représenter uniquement un nom de fichier, jamais un chemin relatif ou absolu.

Validation du fichier source

Le fichier source doit être un fichier régulier.

Le module doit refuser :

  • les dossiers ;
  • les liens symboliques ;
  • les tubes nommés ;
  • les sockets ;
  • les périphériques ;
  • les fichiers absents.

Le contrôle ne doit pas suivre silencieusement un lien symbolique.

Le fichier source doit être ouvert en lecture seule.

Validation du dossier de destination

Le dossier de destination doit :

  • exister ;
  • être un dossier réel ;
  • ne pas être un lien symbolique ;
  • être accessible en écriture.

Le module ne doit pas créer automatiquement le dossier parent dans ce ticket.

La création de l’arborescence de l’enquête relève d’un autre composant.

Construction du chemin final

Le chemin final doit être construit avec les API GLib adaptées, jamais par concaténation fragile.

Exemple :

g_build_filename(
    destination_directory,
    destination_name,
    NULL
);

Le chemin final ne doit jamais sortir du dossier de destination.

Interdiction d’écrasement

Le fichier de destination doit être créé exclusivement.

Une option POSIX adaptée est attendue :

O_CREAT | O_EXCL

Si le fichier existe déjà :

  • aucune donnée ne doit être modifiée ;
  • la fonction doit échouer avec EVIDENCE_COPY_ERROR_DESTINATION_EXISTS.

Il est interdit d’utiliser une stratégie du type :

ouvrir puis tronquer

Le module ne doit jamais écraser une preuve existante.

Copie par blocs

La copie doit être réalisée progressivement.

Le fichier complet ne doit jamais être chargé en mémoire.

Une taille de bloc raisonnable peut être utilisée, par exemple :

64 Kio

La boucle d’écriture doit gérer les écritures partielles.

Un appel à write() peut écrire moins d’octets que demandé. Le module doit poursuivre jusqu’à ce que tout le bloc soit écrit ou qu’une erreur survienne.

Les erreurs EINTR doivent être gérées pour la lecture et l’écriture.

Annulation

Le GCancellable est facultatif.

L’annulation doit être contrôlée :

  • avant le calcul initial du hash ;
  • avant la création de la destination ;
  • avant chaque lecture ;
  • pendant les écritures partielles ;
  • après chaque bloc ;
  • avant la synchronisation ;
  • avant la vérification finale.

En cas d’annulation :

  • la fonction retourne NULL ;
  • une erreur EVIDENCE_COPY_ERROR_CANCELLED est produite ;
  • le fichier destination partiel est fermé ;
  • le fichier destination partiel est supprimé ;
  • le fichier source reste intact.

Le test d’annulation pendant la copie doit être déterministe. Un crochet compilé uniquement pour les tests peut être utilisé, sur le même principe que FileHash.

Synchronisation des données

Après la dernière écriture réussie, le contenu du fichier destination doit être synchronisé avant sa validation.

Une API comme fsync() peut être utilisée sur le descripteur du fichier destination.

Une erreur de synchronisation doit faire échouer la copie et provoquer la suppression du fichier incomplet.

La synchronisation du dossier parent n’est pas obligatoire dans ce ticket, mais peut être documentée comme amélioration future.

Vérification cryptographique

Avant la copie :

source_sha256
source_size

doivent être calculés avec file_hash_compute_sha256().

Après fermeture du fichier destination :

destination_sha256
destination_size

doivent être recalculés avec le même module.

La copie est valide uniquement si :

source_sha256 == destination_sha256
source_size == destination_size

En cas de différence :

  • la fonction échoue avec EVIDENCE_COPY_ERROR_VERIFY ;
  • la copie destination est supprimée ;
  • aucun résultat n’est retourné.

Modification concurrente du fichier source

Le module doit détecter autant que raisonnablement possible une modification du fichier source pendant l’opération.

Le double calcul du hash permet déjà de détecter une différence entre :

  • l’état analysé avant copie ;
  • les octets réellement copiés ;
  • la copie finale.

Une stratégie acceptable consiste à calculer :

  1. le hash source avant copie ;
  2. le hash destination après copie ;
  3. le hash source une seconde fois après copie.

Le succès exige alors :

source_hash_before == destination_hash
source_hash_after == destination_hash
source_size_before == destination_size
source_size_after == destination_size

Cette vérification réduit le risque d’enregistrer une copie issue d’un fichier modifié pendant l’import.

Permissions du fichier destination

La copie doit recevoir des permissions restrictives.

Valeur recommandée :

0600

Le résultat final ne doit pas hériter aveuglément de permissions trop permissives.

Ce ticket ne doit pas tenter de reproduire les permissions du fichier source.

Nettoyage en cas d’échec

Dès que la destination a été créée, toute erreur suivante doit déclencher un nettoyage.

Le nettoyage doit tenter :

  1. de fermer les descripteurs encore ouverts ;
  2. de supprimer le fichier destination ;
  3. de libérer les chaînes et structures ;
  4. de conserver l’erreur principale.

Si la suppression du fichier partiel échoue, le message final doit signaler ce problème sans masquer la cause initiale.

Le module ne doit jamais retourner un résultat partiellement initialisé.

Tests obligatoires

Copie valide d’un fichier texte

Créer un fichier contenant exactement :

abc

Vérifier :

  • création du fichier destination ;
  • contenu identique ;
  • taille égale à 3 ;
  • SHA-256 attendu ;
  • chemin retourné correct ;
  • nom retourné correct ;
  • fichier source inchangé.

Copie d’un fichier vide

Vérifier :

  • création réussie ;
  • taille 0 ;
  • SHA-256 du fichier vide ;
  • fichier destination existant et vide.

Copie binaire

Créer un fichier contenant notamment :

0x00
0xFF
0x80

Vérifier l’identité exacte des octets.

Copie sur plusieurs blocs

Créer un fichier supérieur à la taille du tampon.

Vérifier :

  • taille complète ;
  • hash identique ;
  • contenu identique.

Destination déjà existante

Créer un fichier destination avant l’appel.

Vérifier :

  • retour NULL ;
  • erreur EVIDENCE_COPY_ERROR_DESTINATION_EXISTS ;
  • contenu préexistant inchangé ;
  • fichier source inchangé.

Source absente

Vérifier :

  • erreur dédiée ;
  • aucune destination créée.

Source non régulière

Tester au minimum :

  • dossier ;
  • lien symbolique ;
  • tube nommé.

Aucune destination ne doit être créée.

Destination invalide

Tester :

  • dossier absent ;
  • chemin destination désignant un fichier ;
  • dossier destination symbolique ;
  • nom vide ;
  • nom . ;
  • nom .. ;
  • nom avec / ;
  • nom avec \.

Annulation avant copie

Annuler le GCancellable avant l’appel.

Vérifier :

  • aucune destination créée ;
  • erreur d’annulation.

Annulation pendant copie

Déclencher l’annulation après un nombre déterminé de blocs.

Vérifier :

  • interruption ;
  • aucune copie partielle restante ;
  • fichier source inchangé.

Erreur d’écriture simulée

Prévoir un mécanisme de test interne permettant de simuler une erreur après une quantité déterminée d’octets écrits.

Vérifier :

  • retour en erreur ;
  • suppression du fichier partiel ;
  • aucune fuite.

Le crochet doit être compilé uniquement pour le test.

Échec de vérification simulé

Prévoir un mécanisme déterministe permettant de modifier ou corrompre la destination avant le calcul final.

Vérifier :

  • détection de la différence ;
  • erreur EVIDENCE_COPY_ERROR_VERIFY ;
  • suppression de la destination.

Appels successifs

Copier plusieurs fichiers distincts avec le même module.

Vérifier qu’aucun état interne n’est conservé entre les appels.

Permissions

Vérifier que le fichier destination n’accorde pas de permissions de groupe ou aux autres utilisateurs.

Sur POSIX :

mode & 0077 == 0

Tests de propriété du résultat

Vérifier que :

  • les chaînes retournées restent valides après la fin de la fonction ;
  • elles sont des copies possédées par le résultat ;
  • evidence_copy_result_free(NULL) est accepté ;
  • les accesseurs acceptent NULL et retournent une valeur neutre ;
  • la libération du résultat ne supprime pas la copie validée.

Intégration au Makefile

Ajouter :

tests/test_evidence_copy

aux cibles de test.

La cible devra compiler au minimum :

tests/test_evidence_copy.c
src/core/evidence_copy.c
src/core/file_hash.c

Les crochets de test doivent être activés uniquement pour cette cible.

Critères d’acceptation

Le ticket est validé lorsque :

  • le module compile avec -std=c17 -Wall -Wextra -Werror ;
  • aucune commande shell n’est utilisée ;
  • aucun écrasement n’est possible ;
  • le source n’est jamais modifié ;
  • les liens symboliques et fichiers spéciaux sont refusés ;
  • la copie fonctionne sur plusieurs blocs ;
  • les écritures partielles sont gérées ;
  • l’annulation supprime toute copie partielle ;
  • fsync() est utilisé avant validation ;
  • le SHA-256 et la taille sont vérifiés après copie ;
  • une modification concurrente du source est détectée ;
  • les permissions destination sont restrictives ;
  • tous les tests passent ;
  • git diff --check ne signale rien ;
  • Valgrind ne détecte aucune perte définie ou indirecte.

Commandes de validation

make clean
make
make test
git diff --check

Test ciblé :

./tests/test_evidence_copy

Valgrind :

valgrind \
    --leak-check=full \
    --show-leak-kinds=all \
    --track-origins=yes \
    --errors-for-leak-kinds=definite,indirect \
    --error-exitcode=1 \
    ./tests/test_evidence_copy

Résultats indispensables :

definitely lost: 0 bytes
indirectly lost: 0 bytes
ERROR SUMMARY: 0 errors

Hors périmètre

Ce ticket ne doit pas encore :

  • générer automatiquement le nom final ;
  • sélectionner le sous-dossier de preuve ;
  • créer le EvidenceRecord ;
  • insérer la preuve dans SQLite ;
  • gérer une transaction combinant fichier et base ;
  • afficher une fenêtre GTK ;
  • utiliser BackgroundTask.

Suite prévue

Le ticket suivant orchestrera l’import transactionnel complet :

  1. validation du fichier source ;
  2. génération de l’identifiant et du nom interne ;
  3. copie sûre ;
  4. création du EvidenceRecord ;
  5. insertion SQLite ;
  6. suppression de la copie si l’insertion échoue ;
  7. journalisation de l’opération.
# Copier de façon sûre un fichier de preuve ## Objectif Ajouter un module indépendant capable de copier un fichier source vers l’espace des preuves originales d’une enquête, sans écrasement, sans modification du fichier source et avec vérification cryptographique après copie. Ce module utilisera le calcul SHA-256 déjà disponible pour garantir que la copie produite est strictement identique au fichier source. ## Contexte Le module `FileHash` permet désormais de calculer : - le SHA-256 d’un fichier régulier ; - sa taille exacte ; - avec lecture par blocs ; - avec prise en charge de `GCancellable` ; - sans suivre les liens symboliques. La prochaine étape du futur import de preuves consiste à produire une copie maîtrisée dans l’enquête. Cette copie devra être considérée comme l’original de travail conservé par Labfy Investigation. Le fichier fourni par l’utilisateur doit rester intact. ## Périmètre Créer : ```text include/core/evidence_copy.h src/core/evidence_copy.c tests/test_evidence_copy.c ``` Mettre à jour le `Makefile` afin de compiler le nouveau module et d’exécuter ses tests avec `make test`. ## API attendue Le module doit exposer un résultat opaque ou structuré contenant au minimum : - le chemin final de la copie ; - le nom final du fichier ; - la taille copiée ; - le SHA-256 vérifié. Proposition d’API : ```c 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; #define EVIDENCE_COPY_ERROR evidence_copy_error_quark() GQuark evidence_copy_error_quark(void); typedef struct EvidenceCopyResult EvidenceCopyResult; EvidenceCopyResult *evidence_copy_file( const char *source_path, const char *destination_directory, const char *destination_name, GCancellable *cancellable, GError **error ); void evidence_copy_result_free( EvidenceCopyResult *result ); const char *evidence_copy_result_get_destination_path( const EvidenceCopyResult *result ); const char *evidence_copy_result_get_destination_name( const EvidenceCopyResult *result ); const char *evidence_copy_result_get_sha256( const EvidenceCopyResult *result ); guint64 evidence_copy_result_get_size_bytes( const EvidenceCopyResult *result ); ``` L’API exacte peut être adaptée, mais le résultat retourné doit rester immuable pour l’appelant et propriétaire de ses chaînes. ## Responsabilités du module Le module doit : 1. valider le fichier source ; 2. valider le dossier de destination ; 3. valider le nom de destination ; 4. calculer le SHA-256 et la taille du fichier source ; 5. créer exclusivement un nouveau fichier ; 6. copier les données par blocs ; 7. synchroniser les données écrites ; 8. fermer le fichier de destination ; 9. recalculer le SHA-256 et la taille de la copie ; 10. comparer source et destination ; 11. supprimer toute copie incomplète ou invalide en cas d’échec ; 12. retourner un résultat uniquement après validation complète. ## Hors responsabilité Le module ne doit pas : - créer un `EvidenceRecord` ; - insérer une preuve dans SQLite ; - choisir automatiquement le sous-dossier métier ; - générer l’identifiant UUID ; - afficher une fenêtre GTK ; - modifier le fichier source ; - extraire les métadonnées du fichier ; - lancer une commande shell ; - interpréter le contenu du fichier. ## Validation des paramètres La fonction doit refuser : - un chemin source `NULL` ou vide ; - un dossier de destination `NULL` ou vide ; - un nom de destination `NULL` ou vide ; - un nom égal à `.` ou `..` ; - un nom contenant `/` ; - un nom contenant `\` ; - un nom possédant un composant de chemin ; - un `GError` déjà initialisé. Le nom fourni doit représenter uniquement un nom de fichier, jamais un chemin relatif ou absolu. ## Validation du fichier source Le fichier source doit être un fichier régulier. Le module doit refuser : - les dossiers ; - les liens symboliques ; - les tubes nommés ; - les sockets ; - les périphériques ; - les fichiers absents. Le contrôle ne doit pas suivre silencieusement un lien symbolique. Le fichier source doit être ouvert en lecture seule. ## Validation du dossier de destination Le dossier de destination doit : - exister ; - être un dossier réel ; - ne pas être un lien symbolique ; - être accessible en écriture. Le module ne doit pas créer automatiquement le dossier parent dans ce ticket. La création de l’arborescence de l’enquête relève d’un autre composant. ## Construction du chemin final Le chemin final doit être construit avec les API GLib adaptées, jamais par concaténation fragile. Exemple : ```c g_build_filename( destination_directory, destination_name, NULL ); ``` Le chemin final ne doit jamais sortir du dossier de destination. ## Interdiction d’écrasement Le fichier de destination doit être créé exclusivement. Une option POSIX adaptée est attendue : ```text O_CREAT | O_EXCL ``` Si le fichier existe déjà : - aucune donnée ne doit être modifiée ; - la fonction doit échouer avec `EVIDENCE_COPY_ERROR_DESTINATION_EXISTS`. Il est interdit d’utiliser une stratégie du type : ```text ouvrir puis tronquer ``` Le module ne doit jamais écraser une preuve existante. ## Copie par blocs La copie doit être réalisée progressivement. Le fichier complet ne doit jamais être chargé en mémoire. Une taille de bloc raisonnable peut être utilisée, par exemple : ```text 64 Kio ``` La boucle d’écriture doit gérer les écritures partielles. Un appel à `write()` peut écrire moins d’octets que demandé. Le module doit poursuivre jusqu’à ce que tout le bloc soit écrit ou qu’une erreur survienne. Les erreurs `EINTR` doivent être gérées pour la lecture et l’écriture. ## Annulation Le `GCancellable` est facultatif. L’annulation doit être contrôlée : - avant le calcul initial du hash ; - avant la création de la destination ; - avant chaque lecture ; - pendant les écritures partielles ; - après chaque bloc ; - avant la synchronisation ; - avant la vérification finale. En cas d’annulation : - la fonction retourne `NULL` ; - une erreur `EVIDENCE_COPY_ERROR_CANCELLED` est produite ; - le fichier destination partiel est fermé ; - le fichier destination partiel est supprimé ; - le fichier source reste intact. Le test d’annulation pendant la copie doit être déterministe. Un crochet compilé uniquement pour les tests peut être utilisé, sur le même principe que `FileHash`. ## Synchronisation des données Après la dernière écriture réussie, le contenu du fichier destination doit être synchronisé avant sa validation. Une API comme `fsync()` peut être utilisée sur le descripteur du fichier destination. Une erreur de synchronisation doit faire échouer la copie et provoquer la suppression du fichier incomplet. La synchronisation du dossier parent n’est pas obligatoire dans ce ticket, mais peut être documentée comme amélioration future. ## Vérification cryptographique Avant la copie : ```text source_sha256 source_size ``` doivent être calculés avec `file_hash_compute_sha256()`. Après fermeture du fichier destination : ```text destination_sha256 destination_size ``` doivent être recalculés avec le même module. La copie est valide uniquement si : ```text source_sha256 == destination_sha256 source_size == destination_size ``` En cas de différence : - la fonction échoue avec `EVIDENCE_COPY_ERROR_VERIFY` ; - la copie destination est supprimée ; - aucun résultat n’est retourné. ## Modification concurrente du fichier source Le module doit détecter autant que raisonnablement possible une modification du fichier source pendant l’opération. Le double calcul du hash permet déjà de détecter une différence entre : - l’état analysé avant copie ; - les octets réellement copiés ; - la copie finale. Une stratégie acceptable consiste à calculer : 1. le hash source avant copie ; 2. le hash destination après copie ; 3. le hash source une seconde fois après copie. Le succès exige alors : ```text source_hash_before == destination_hash source_hash_after == destination_hash source_size_before == destination_size source_size_after == destination_size ``` Cette vérification réduit le risque d’enregistrer une copie issue d’un fichier modifié pendant l’import. ## Permissions du fichier destination La copie doit recevoir des permissions restrictives. Valeur recommandée : ```text 0600 ``` Le résultat final ne doit pas hériter aveuglément de permissions trop permissives. Ce ticket ne doit pas tenter de reproduire les permissions du fichier source. ## Nettoyage en cas d’échec Dès que la destination a été créée, toute erreur suivante doit déclencher un nettoyage. Le nettoyage doit tenter : 1. de fermer les descripteurs encore ouverts ; 2. de supprimer le fichier destination ; 3. de libérer les chaînes et structures ; 4. de conserver l’erreur principale. Si la suppression du fichier partiel échoue, le message final doit signaler ce problème sans masquer la cause initiale. Le module ne doit jamais retourner un résultat partiellement initialisé. ## Tests obligatoires ### Copie valide d’un fichier texte Créer un fichier contenant exactement : ```text abc ``` Vérifier : - création du fichier destination ; - contenu identique ; - taille égale à `3` ; - SHA-256 attendu ; - chemin retourné correct ; - nom retourné correct ; - fichier source inchangé. ### Copie d’un fichier vide Vérifier : - création réussie ; - taille `0` ; - SHA-256 du fichier vide ; - fichier destination existant et vide. ### Copie binaire Créer un fichier contenant notamment : ```text 0x00 0xFF 0x80 ``` Vérifier l’identité exacte des octets. ### Copie sur plusieurs blocs Créer un fichier supérieur à la taille du tampon. Vérifier : - taille complète ; - hash identique ; - contenu identique. ### Destination déjà existante Créer un fichier destination avant l’appel. Vérifier : - retour `NULL` ; - erreur `EVIDENCE_COPY_ERROR_DESTINATION_EXISTS` ; - contenu préexistant inchangé ; - fichier source inchangé. ### Source absente Vérifier : - erreur dédiée ; - aucune destination créée. ### Source non régulière Tester au minimum : - dossier ; - lien symbolique ; - tube nommé. Aucune destination ne doit être créée. ### Destination invalide Tester : - dossier absent ; - chemin destination désignant un fichier ; - dossier destination symbolique ; - nom vide ; - nom `.` ; - nom `..` ; - nom avec `/` ; - nom avec `\`. ### Annulation avant copie Annuler le `GCancellable` avant l’appel. Vérifier : - aucune destination créée ; - erreur d’annulation. ### Annulation pendant copie Déclencher l’annulation après un nombre déterminé de blocs. Vérifier : - interruption ; - aucune copie partielle restante ; - fichier source inchangé. ### Erreur d’écriture simulée Prévoir un mécanisme de test interne permettant de simuler une erreur après une quantité déterminée d’octets écrits. Vérifier : - retour en erreur ; - suppression du fichier partiel ; - aucune fuite. Le crochet doit être compilé uniquement pour le test. ### Échec de vérification simulé Prévoir un mécanisme déterministe permettant de modifier ou corrompre la destination avant le calcul final. Vérifier : - détection de la différence ; - erreur `EVIDENCE_COPY_ERROR_VERIFY` ; - suppression de la destination. ### Appels successifs Copier plusieurs fichiers distincts avec le même module. Vérifier qu’aucun état interne n’est conservé entre les appels. ### Permissions Vérifier que le fichier destination n’accorde pas de permissions de groupe ou aux autres utilisateurs. Sur POSIX : ```text mode & 0077 == 0 ``` ## Tests de propriété du résultat Vérifier que : - les chaînes retournées restent valides après la fin de la fonction ; - elles sont des copies possédées par le résultat ; - `evidence_copy_result_free(NULL)` est accepté ; - les accesseurs acceptent `NULL` et retournent une valeur neutre ; - la libération du résultat ne supprime pas la copie validée. ## Intégration au Makefile Ajouter : ```text tests/test_evidence_copy ``` aux cibles de test. La cible devra compiler au minimum : ```text tests/test_evidence_copy.c src/core/evidence_copy.c src/core/file_hash.c ``` Les crochets de test doivent être activés uniquement pour cette cible. ## Critères d’acceptation Le ticket est validé lorsque : - le module compile avec `-std=c17 -Wall -Wextra -Werror` ; - aucune commande shell n’est utilisée ; - aucun écrasement n’est possible ; - le source n’est jamais modifié ; - les liens symboliques et fichiers spéciaux sont refusés ; - la copie fonctionne sur plusieurs blocs ; - les écritures partielles sont gérées ; - l’annulation supprime toute copie partielle ; - `fsync()` est utilisé avant validation ; - le SHA-256 et la taille sont vérifiés après copie ; - une modification concurrente du source est détectée ; - les permissions destination sont restrictives ; - tous les tests passent ; - `git diff --check` ne signale rien ; - Valgrind ne détecte aucune perte définie ou indirecte. ## Commandes de validation ```bash make clean make make test git diff --check ``` Test ciblé : ```bash ./tests/test_evidence_copy ``` Valgrind : ```bash valgrind \ --leak-check=full \ --show-leak-kinds=all \ --track-origins=yes \ --errors-for-leak-kinds=definite,indirect \ --error-exitcode=1 \ ./tests/test_evidence_copy ``` Résultats indispensables : ```text definitely lost: 0 bytes indirectly lost: 0 bytes ERROR SUMMARY: 0 errors ``` ## Hors périmètre Ce ticket ne doit pas encore : - générer automatiquement le nom final ; - sélectionner le sous-dossier de preuve ; - créer le `EvidenceRecord` ; - insérer la preuve dans SQLite ; - gérer une transaction combinant fichier et base ; - afficher une fenêtre GTK ; - utiliser `BackgroundTask`. ## Suite prévue Le ticket suivant orchestrera l’import transactionnel complet : 1. validation du fichier source ; 2. génération de l’identifiant et du nom interne ; 3. copie sûre ; 4. création du `EvidenceRecord` ; 5. insertion SQLite ; 6. suppression de la copie si l’insertion échoue ; 7. journalisation de l’opération.
fy59 closed this issue 2026-07-19 16:51:36 +02:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: fy59/labfy-investigation#48
No description provided.