/* Chrysalide - Outil d'analyse de fichiers binaires * cache.c - conservation hors mémoire d'objets choisis * * Copyright (C) 2020 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . */ #include "cache.h" #include #include #include #include #include "cache-int.h" #include "../../core/logs.h" /* Initialise la classe des caches d'objets entreposables. */ static void g_object_cache_class_init(GObjectCacheClass *); /* Initialise une instance de cache d'objets entreposables. */ static void g_object_cache_init(GObjectCache *); /* Supprime toutes les références externes. */ static void g_object_cache_dispose(GObjectCache *); /* Procède à la libération totale de la mémoire. */ static void g_object_cache_finalize(GObjectCache *); /* Indique le type défini pour un cache d'objets entreposables. */ G_DEFINE_TYPE(GObjectCache, g_object_cache, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des caches d'objets entreposables. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_object_cache_class_init(GObjectCacheClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_object_cache_dispose; object->finalize = (GObjectFinalizeFunc)g_object_cache_finalize; } /****************************************************************************** * * * Paramètres : cache = instance à initialiser. * * * * Description : Initialise une instance de cache d'objets entreposables. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_object_cache_init(GObjectCache *cache) { cache->loaded = NULL; cache->filename = NULL; cache->fd = -1; cache->containers = NULL; cache->count = 0; cache->free_ptr = 0; g_mutex_init(&cache->mutex); } /****************************************************************************** * * * Paramètres : cache = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_object_cache_dispose(GObjectCache *cache) { size_t i; /* Boucle de parcours */ g_clear_object(&cache->loaded); g_mutex_lock(&cache->mutex); for (i = 0; i < cache->count; i++) g_clear_object(&cache->containers[i]); g_mutex_unlock(&cache->mutex); g_mutex_clear(&cache->mutex); G_OBJECT_CLASS(g_object_cache_parent_class)->dispose(G_OBJECT(cache)); } /****************************************************************************** * * * Paramètres : cache = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_object_cache_finalize(GObjectCache *cache) { int ret; /* Bilan d'un appel */ ret = access(cache->filename, W_OK); if (ret == 0) { ret = unlink(cache->filename); if (ret != 0) LOG_ERROR_N("unlink"); } free(cache->filename); if (cache->containers != NULL) free(cache->containers); G_OBJECT_CLASS(g_object_cache_parent_class)->finalize(G_OBJECT(cache)); } /****************************************************************************** * * * Paramètres : loaded = contenu binaire à associer. * * * * Description : Crée le support d'un cache d'objets entreposables. * * * * Retour : Mécanismes mis en place. * * * * Remarques : - * * * ******************************************************************************/ GObjectCache *g_object_cache_new(GLoadedContent *loaded) { GObjectCache *result; /* Structure à retourner */ result = g_object_new(G_TYPE_OBJECT_CACHE, NULL); if (!g_object_cache_open_for(result, loaded)) { g_object_unref(G_OBJECT(result)); result = NULL; } return result; } /****************************************************************************** * * * Paramètres : cache = cache d'objets à manipuler. * * loaded = contenu binaire à associer. * * * * Description : Associe un contenu à un cache d'objets. * * * * Retour : Bilan de l'opéation. * * * * Remarques : - * * * ******************************************************************************/ bool g_object_cache_open_for(GObjectCache *cache, GLoadedContent *loaded) { bool result; /* Bilan à retourner */ GBinContent *content; /* Contenu binaire traité */ const gchar *checksum; /* Empreinte de ce contenu */ result = (cache->loaded == NULL); assert(result); if (result) goto done; cache->loaded = loaded; g_object_ref(G_OBJECT(loaded)); /* Constitution du fichier de cache */ content = g_loaded_content_get_content(loaded); checksum = g_binary_content_get_checksum(content); asprintf(&cache->filename, "/dev/shm/%s.cache", checksum); g_object_unref(G_OBJECT(content)); /* Ouverture dudit fichier */ cache->fd = open(cache->filename, O_CREAT | O_TRUNC | O_LARGEFILE, 0600); if (cache->fd == -1) { LOG_ERROR_N("open"); result = false; goto done; } /* Préparation du cache */ cache->count = 1000; cache->containers = calloc(cache->count, sizeof(GCacheContainer *)); result = true; done: return result; } /****************************************************************************** * * * Paramètres : cache = cache d'objets à manipuler. * * container = objet à placer dans le cache. * * * * Description : Introduit un contenu dans un cache d'objets. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_object_cache_add(GObjectCache *cache, GCacheContainer *container) { bool loop; /* Détection de trop-plein */ size_t i; /* Boucle de parcours */ /* Recherche d'un emplacement libre */ loop = false; i = cache->free_ptr; do { if (cache->containers[i] != NULL) { g_cache_container_lock_unlock(cache->containers[i], true); if (g_cache_container_can_store(cache->containers[i])) { if (true) // TODO g_clear_object(&cache->containers[i]); } g_cache_container_lock_unlock(cache->containers[i], false); } if (cache->containers[i] == NULL) break; i++; if (i == cache->count) i = 0; loop = (i == cache->free_ptr); } while (!loop); if (loop) { log_simple_message(LMT_WARNING, _("Instruction cache is full!")); goto exit; } /* Inscription à la liste des sursis */ cache->containers[i] = container; cache->free_ptr = (i + 1); if (cache->free_ptr == cache->count) cache->free_ptr = 0; exit: ; }