feat: compute evidence file sha256
This commit is contained in:
parent
c7bf0da4e6
commit
d6fb7c0e46
6 changed files with 2021 additions and 2 deletions
16
Makefile
16
Makefile
|
|
@ -52,6 +52,7 @@ TEST_TOOL_PROCESS := tests/test_tool_process
|
||||||
TEST_TOOL_TASK := tests/test_tool_task
|
TEST_TOOL_TASK := tests/test_tool_task
|
||||||
TEST_TOOL_CATALOG := tests/test_tool_catalog
|
TEST_TOOL_CATALOG := tests/test_tool_catalog
|
||||||
TEST_TOOL_INITIALIZER := tests/test_tool_initializer
|
TEST_TOOL_INITIALIZER := tests/test_tool_initializer
|
||||||
|
TEST_FILE_HASH := tests/test_file_hash
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
|
|
@ -212,6 +213,13 @@ $(TEST_TOOL_INITIALIZER): \
|
||||||
src/core/tool_process.c
|
src/core/tool_process.c
|
||||||
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
|
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
|
||||||
|
|
||||||
|
$(TEST_FILE_HASH): \
|
||||||
|
tests/test_file_hash.c \
|
||||||
|
src/core/file_hash.c
|
||||||
|
$(CC) $(TEST_CFLAGS) \
|
||||||
|
-DFILE_HASH_ENABLE_TEST_HOOKS \
|
||||||
|
$^ -o $@ $(TEST_LDFLAGS)
|
||||||
|
|
||||||
test: \
|
test: \
|
||||||
$(TEST_NODE) \
|
$(TEST_NODE) \
|
||||||
$(TEST_TREE_MODEL) \
|
$(TEST_TREE_MODEL) \
|
||||||
|
|
@ -232,7 +240,8 @@ test: \
|
||||||
$(TEST_TOOL_PROCESS) \
|
$(TEST_TOOL_PROCESS) \
|
||||||
$(TEST_TOOL_TASK) \
|
$(TEST_TOOL_TASK) \
|
||||||
$(TEST_TOOL_CATALOG) \
|
$(TEST_TOOL_CATALOG) \
|
||||||
$(TEST_TOOL_INITIALIZER)
|
$(TEST_TOOL_INITIALIZER) \
|
||||||
|
$(TEST_FILE_HASH)
|
||||||
@echo "Exécution des tests..."
|
@echo "Exécution des tests..."
|
||||||
@./$(TEST_NODE)
|
@./$(TEST_NODE)
|
||||||
@./$(TEST_TREE_MODEL)
|
@./$(TEST_TREE_MODEL)
|
||||||
|
|
@ -254,6 +263,7 @@ test: \
|
||||||
@$(TEST_TOOL_TASK)
|
@$(TEST_TOOL_TASK)
|
||||||
@$(TEST_TOOL_CATALOG)
|
@$(TEST_TOOL_CATALOG)
|
||||||
@$(TEST_TOOL_INITIALIZER)
|
@$(TEST_TOOL_INITIALIZER)
|
||||||
|
@$(TEST_FILE_HASH)
|
||||||
@echo "Tous les tests sont valides."
|
@echo "Tous les tests sont valides."
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
|
|
@ -283,6 +293,8 @@ clean:
|
||||||
$(TEST_TOOL_PROCESS) \
|
$(TEST_TOOL_PROCESS) \
|
||||||
$(TEST_TOOL_TASK) \
|
$(TEST_TOOL_TASK) \
|
||||||
$(TEST_TOOL_CATALOG) \
|
$(TEST_TOOL_CATALOG) \
|
||||||
$(TEST_TOOL_INITIALIZER)
|
$(TEST_TOOL_INITIALIZER) \
|
||||||
|
$(TEST_FILE_HASH)
|
||||||
|
|
||||||
|
|
||||||
.PHONY: clean run test
|
.PHONY: clean run test
|
||||||
|
|
|
||||||
99
include/core/file_hash.h
Normal file
99
include/core/file_hash.h
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file file_hash.h
|
||||||
|
* @brief Calcul des empreintes cryptographiques des fichiers de preuve.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LABFY_INVESTIGATION_FILE_HASH_H
|
||||||
|
#define LABFY_INVESTIGATION_FILE_HASH_H
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Catégories d’erreurs du module FileHash.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
FILE_HASH_ERROR_INVALID_ARGUMENT,
|
||||||
|
FILE_HASH_ERROR_NOT_FOUND,
|
||||||
|
FILE_HASH_ERROR_NOT_REGULAR,
|
||||||
|
FILE_HASH_ERROR_OPEN,
|
||||||
|
FILE_HASH_ERROR_READ,
|
||||||
|
FILE_HASH_ERROR_CANCELLED,
|
||||||
|
FILE_HASH_ERROR_MEMORY
|
||||||
|
} FileHashError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Domaine d’erreurs du module FileHash.
|
||||||
|
*/
|
||||||
|
#define FILE_HASH_ERROR \
|
||||||
|
file_hash_error_quark()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne le domaine d’erreurs du module FileHash.
|
||||||
|
*/
|
||||||
|
GQuark file_hash_error_quark(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calcule le SHA-256 et la taille d’un fichier régulier.
|
||||||
|
*
|
||||||
|
* Le fichier est lu progressivement et n’est jamais chargé intégralement
|
||||||
|
* en mémoire.
|
||||||
|
*
|
||||||
|
* Le chemin final ne doit pas être un lien symbolique.
|
||||||
|
*
|
||||||
|
* Avant l’appel :
|
||||||
|
*
|
||||||
|
* - out_sha256 doit être valide ;
|
||||||
|
* - *out_sha256 doit valoir NULL ;
|
||||||
|
* - out_size_bytes doit être valide ;
|
||||||
|
* - error doit être NULL ou pointer vers NULL.
|
||||||
|
*
|
||||||
|
* Après un succès :
|
||||||
|
*
|
||||||
|
* - *out_sha256 contient une chaîne de 64 caractères hexadécimaux
|
||||||
|
* minuscules, à libérer avec g_free() ;
|
||||||
|
* - *out_size_bytes contient le nombre d’octets effectivement lus.
|
||||||
|
*
|
||||||
|
* Après un échec :
|
||||||
|
*
|
||||||
|
* - *out_sha256 reste NULL ;
|
||||||
|
* - *out_size_bytes vaut 0.
|
||||||
|
*
|
||||||
|
* @param file_path Chemin du fichier à analyser.
|
||||||
|
* @param cancellable Objet d’annulation facultatif.
|
||||||
|
* @param out_sha256 Destination de la chaîne SHA-256.
|
||||||
|
* @param out_size_bytes Destination de la taille du fichier.
|
||||||
|
* @param error Adresse recevant une éventuelle erreur.
|
||||||
|
*
|
||||||
|
* @return TRUE en cas de succès, sinon FALSE.
|
||||||
|
*/
|
||||||
|
gboolean file_hash_compute_sha256(
|
||||||
|
const char *file_path,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
char **out_sha256,
|
||||||
|
guint64 *out_size_bytes,
|
||||||
|
GError **error
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef FILE_HASH_ENABLE_TEST_HOOKS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crochet appelé après chaque bloc lu, réservé aux tests.
|
||||||
|
*/
|
||||||
|
typedef void (*FileHashTestBlockHook)(
|
||||||
|
guint64 total_size_bytes,
|
||||||
|
gpointer user_data
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configure le crochet de lecture réservé aux tests.
|
||||||
|
*/
|
||||||
|
void file_hash_test_set_block_hook(
|
||||||
|
FileHashTestBlockHook block_hook,
|
||||||
|
gpointer user_data
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
Binary file not shown.
553
src/core/file_hash.c
Normal file
553
src/core/file_hash.c
Normal file
|
|
@ -0,0 +1,553 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file file_hash.c
|
||||||
|
* @brief Calcul progressif du SHA-256 des fichiers de preuve.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
|
#include "core/file_hash.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Taille du tampon de lecture.
|
||||||
|
*/
|
||||||
|
#define FILE_HASH_BLOCK_SIZE (64U * 1024U)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Nombre d’octets composant un SHA-256.
|
||||||
|
*/
|
||||||
|
#define FILE_HASH_SHA256_DIGEST_SIZE 32U
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Nombre de caractères hexadécimaux composant un SHA-256.
|
||||||
|
*/
|
||||||
|
#define FILE_HASH_SHA256_TEXT_SIZE 64U
|
||||||
|
|
||||||
|
#ifdef FILE_HASH_ENABLE_TEST_HOOKS
|
||||||
|
|
||||||
|
static FileHashTestBlockHook file_hash_test_block_hook = NULL;
|
||||||
|
static gpointer file_hash_test_block_hook_data = NULL;
|
||||||
|
|
||||||
|
void file_hash_test_set_block_hook(
|
||||||
|
FileHashTestBlockHook block_hook,
|
||||||
|
gpointer user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
file_hash_test_block_hook = block_hook;
|
||||||
|
file_hash_test_block_hook_data = user_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_hash_test_notify_block(
|
||||||
|
guint64 total_size_bytes
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (file_hash_test_block_hook == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_hash_test_block_hook(
|
||||||
|
total_size_bytes,
|
||||||
|
file_hash_test_block_hook_data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static void file_hash_test_notify_block(
|
||||||
|
guint64 total_size_bytes
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Le paramètre est volontairement inutilisé dans la version
|
||||||
|
* de production.
|
||||||
|
*/
|
||||||
|
(void) total_size_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enregistre une erreur littérale.
|
||||||
|
*/
|
||||||
|
static void file_hash_set_error_literal(
|
||||||
|
GError **error,
|
||||||
|
FileHashError error_code,
|
||||||
|
const char *error_message
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (error == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR,
|
||||||
|
error_code,
|
||||||
|
error_message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enregistre une erreur contenant un chemin et une erreur système.
|
||||||
|
*/
|
||||||
|
static void file_hash_set_system_error(
|
||||||
|
GError **error,
|
||||||
|
FileHashError error_code,
|
||||||
|
const char *context,
|
||||||
|
const char *file_path,
|
||||||
|
int system_error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (error == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_set_error(
|
||||||
|
error,
|
||||||
|
FILE_HASH_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 file_hash_check_cancelled(
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (cancellable == NULL ||
|
||||||
|
!g_cancellable_is_cancelled(cancellable))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_hash_set_error_literal(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_CANCELLED,
|
||||||
|
"Le calcul du SHA-256 a été annulé."
|
||||||
|
);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convertit le condensat SHA-256 en texte hexadécimal minuscule.
|
||||||
|
*/
|
||||||
|
static char *file_hash_digest_to_hex(
|
||||||
|
const guint8 *digest,
|
||||||
|
gsize digest_size,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
static const char hexadecimal_digits[] =
|
||||||
|
"0123456789abcdef";
|
||||||
|
|
||||||
|
char *sha256 = NULL;
|
||||||
|
gsize digest_index = 0;
|
||||||
|
|
||||||
|
if (digest == NULL ||
|
||||||
|
digest_size != FILE_HASH_SHA256_DIGEST_SIZE)
|
||||||
|
{
|
||||||
|
file_hash_set_error_literal(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_INVALID_ARGUMENT,
|
||||||
|
"Le condensat SHA-256 est invalide."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sha256 = g_try_malloc0(
|
||||||
|
FILE_HASH_SHA256_TEXT_SIZE + 1U
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sha256 == NULL)
|
||||||
|
{
|
||||||
|
file_hash_set_error_literal(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_MEMORY,
|
||||||
|
"Impossible d’allouer la chaîne SHA-256."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (digest_index = 0;
|
||||||
|
digest_index < digest_size;
|
||||||
|
digest_index++)
|
||||||
|
{
|
||||||
|
sha256[digest_index * 2U] =
|
||||||
|
hexadecimal_digits[
|
||||||
|
digest[digest_index] >> 4U
|
||||||
|
];
|
||||||
|
|
||||||
|
sha256[digest_index * 2U + 1U] =
|
||||||
|
hexadecimal_digits[
|
||||||
|
digest[digest_index] & 0x0FU
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return sha256;
|
||||||
|
}
|
||||||
|
|
||||||
|
GQuark file_hash_error_quark(void)
|
||||||
|
{
|
||||||
|
return g_quark_from_static_string(
|
||||||
|
"file-hash-error-quark"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean file_hash_compute_sha256(
|
||||||
|
const char *file_path,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
char **out_sha256,
|
||||||
|
guint64 *out_size_bytes,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
GChecksum *checksum = NULL;
|
||||||
|
|
||||||
|
guint8 *read_buffer = NULL;
|
||||||
|
guint8 digest[FILE_HASH_SHA256_DIGEST_SIZE];
|
||||||
|
|
||||||
|
struct stat file_status;
|
||||||
|
|
||||||
|
char *sha256 = NULL;
|
||||||
|
|
||||||
|
gsize digest_size =
|
||||||
|
FILE_HASH_SHA256_DIGEST_SIZE;
|
||||||
|
|
||||||
|
guint64 total_size_bytes = 0;
|
||||||
|
|
||||||
|
ssize_t read_size = 0;
|
||||||
|
|
||||||
|
int file_descriptor = -1;
|
||||||
|
int saved_errno = 0;
|
||||||
|
|
||||||
|
gboolean success = FALSE;
|
||||||
|
|
||||||
|
g_return_val_if_fail(
|
||||||
|
error == NULL || *error == NULL,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
|
||||||
|
if (out_size_bytes != NULL)
|
||||||
|
{
|
||||||
|
*out_size_bytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_path == NULL ||
|
||||||
|
file_path[0] == '\0' ||
|
||||||
|
out_sha256 == NULL ||
|
||||||
|
out_size_bytes == NULL)
|
||||||
|
{
|
||||||
|
file_hash_set_error_literal(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_INVALID_ARGUMENT,
|
||||||
|
"Les paramètres du calcul SHA-256 sont invalides."
|
||||||
|
);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Le module ne doit jamais libérer une ancienne chaîne appartenant
|
||||||
|
* à l’appelant.
|
||||||
|
*/
|
||||||
|
if (*out_sha256 != NULL)
|
||||||
|
{
|
||||||
|
file_hash_set_error_literal(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_INVALID_ARGUMENT,
|
||||||
|
"La destination SHA-256 doit initialement valoir NULL."
|
||||||
|
);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_hash_check_cancelled(
|
||||||
|
cancellable,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* O_NOFOLLOW refuse un lien symbolique utilisé comme dernier composant.
|
||||||
|
*
|
||||||
|
* O_NONBLOCK évite de rester bloqué lors de l’ouverture accidentelle
|
||||||
|
* d’un tube nommé ou d’un fichier spécial.
|
||||||
|
*/
|
||||||
|
file_descriptor = open(
|
||||||
|
file_path,
|
||||||
|
O_RDONLY |
|
||||||
|
O_CLOEXEC |
|
||||||
|
O_NOFOLLOW |
|
||||||
|
O_NONBLOCK
|
||||||
|
);
|
||||||
|
|
||||||
|
if (file_descriptor < 0)
|
||||||
|
{
|
||||||
|
saved_errno = errno;
|
||||||
|
|
||||||
|
if (saved_errno == ENOENT ||
|
||||||
|
saved_errno == ENOTDIR)
|
||||||
|
{
|
||||||
|
file_hash_set_system_error(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_NOT_FOUND,
|
||||||
|
"Le fichier est introuvable",
|
||||||
|
file_path,
|
||||||
|
saved_errno
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (saved_errno == ELOOP)
|
||||||
|
{
|
||||||
|
file_hash_set_error_literal(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_NOT_REGULAR,
|
||||||
|
"Le chemin désigne un lien symbolique."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file_hash_set_system_error(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_OPEN,
|
||||||
|
"Impossible d’ouvrir le fichier",
|
||||||
|
file_path,
|
||||||
|
saved_errno
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fstat(
|
||||||
|
file_descriptor,
|
||||||
|
&file_status
|
||||||
|
) != 0)
|
||||||
|
{
|
||||||
|
saved_errno = errno;
|
||||||
|
|
||||||
|
file_hash_set_system_error(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_OPEN,
|
||||||
|
"Impossible d’inspecter le fichier",
|
||||||
|
file_path,
|
||||||
|
saved_errno
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!S_ISREG(file_status.st_mode))
|
||||||
|
{
|
||||||
|
file_hash_set_error_literal(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_NOT_REGULAR,
|
||||||
|
"Le chemin ne désigne pas un fichier régulier."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_hash_check_cancelled(
|
||||||
|
cancellable,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
checksum = g_checksum_new(
|
||||||
|
G_CHECKSUM_SHA256
|
||||||
|
);
|
||||||
|
|
||||||
|
if (checksum == NULL)
|
||||||
|
{
|
||||||
|
file_hash_set_error_literal(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_MEMORY,
|
||||||
|
"Impossible d’allouer le calculateur SHA-256."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_buffer = g_try_malloc(
|
||||||
|
FILE_HASH_BLOCK_SIZE
|
||||||
|
);
|
||||||
|
|
||||||
|
if (read_buffer == NULL)
|
||||||
|
{
|
||||||
|
file_hash_set_error_literal(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_MEMORY,
|
||||||
|
"Impossible d’allouer le tampon de lecture."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
if (file_hash_check_cancelled(
|
||||||
|
cancellable,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_size = read(
|
||||||
|
file_descriptor,
|
||||||
|
read_buffer,
|
||||||
|
FILE_HASH_BLOCK_SIZE
|
||||||
|
);
|
||||||
|
|
||||||
|
if (read_size < 0)
|
||||||
|
{
|
||||||
|
saved_errno = errno;
|
||||||
|
|
||||||
|
if (saved_errno == EINTR)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_hash_set_system_error(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_READ,
|
||||||
|
"Impossible de lire le fichier",
|
||||||
|
file_path,
|
||||||
|
saved_errno
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read_size == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_checksum_update(
|
||||||
|
checksum,
|
||||||
|
read_buffer,
|
||||||
|
(gssize) read_size
|
||||||
|
);
|
||||||
|
|
||||||
|
total_size_bytes +=
|
||||||
|
(guint64) read_size;
|
||||||
|
|
||||||
|
file_hash_test_notify_block(
|
||||||
|
total_size_bytes
|
||||||
|
);
|
||||||
|
|
||||||
|
if (file_hash_check_cancelled(
|
||||||
|
cancellable,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_hash_check_cancelled(
|
||||||
|
cancellable,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_checksum_get_digest(
|
||||||
|
checksum,
|
||||||
|
digest,
|
||||||
|
&digest_size
|
||||||
|
);
|
||||||
|
|
||||||
|
if (digest_size !=
|
||||||
|
FILE_HASH_SHA256_DIGEST_SIZE)
|
||||||
|
{
|
||||||
|
file_hash_set_error_literal(
|
||||||
|
error,
|
||||||
|
FILE_HASH_ERROR_READ,
|
||||||
|
"La taille du condensat SHA-256 est invalide."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
sha256 = file_hash_digest_to_hex(
|
||||||
|
digest,
|
||||||
|
digest_size,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sha256 == NULL)
|
||||||
|
{
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Les sorties ne sont publiées qu’après le succès complet.
|
||||||
|
*/
|
||||||
|
*out_sha256 = sha256;
|
||||||
|
*out_size_bytes = total_size_bytes;
|
||||||
|
|
||||||
|
sha256 = NULL;
|
||||||
|
success = TRUE;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
sha256
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
read_buffer
|
||||||
|
);
|
||||||
|
|
||||||
|
if (checksum != NULL)
|
||||||
|
{
|
||||||
|
g_checksum_free(
|
||||||
|
checksum
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_descriptor >= 0)
|
||||||
|
{
|
||||||
|
if (close(
|
||||||
|
file_descriptor
|
||||||
|
) != 0 &&
|
||||||
|
success)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Une erreur de fermeture en lecture seule ne modifie pas
|
||||||
|
* le condensat déjà calculé. Elle est néanmoins signalée.
|
||||||
|
*/
|
||||||
|
g_warning(
|
||||||
|
"Impossible de fermer proprement le fichier '%s' : %s",
|
||||||
|
file_path,
|
||||||
|
g_strerror(errno)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
BIN
tests/test_file_hash
Executable file
BIN
tests/test_file_hash
Executable file
Binary file not shown.
1355
tests/test_file_hash.c
Normal file
1355
tests/test_file_hash.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue