/* Chrysalide - Outil d'analyse de fichiers binaires
* compression.c - facilités de manipulation des archives
*
* Copyright (C) 2018 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 Chrysalide. If not, see .
*/
#include "compression.h"
#include
#include
#include
#include "io.h"
#include "../analysis/contents/memory.h"
/* Fixe le tampon pour la lecture des fichiers à inclure */
#define ARCHIVE_RBUF_SIZE 2048
/******************************************************************************
* *
* Paramètres : output = archive dont le contenu est à composer. *
* filename = chemin d'accès au fichier d'entrée. *
* path = chemin d'accès dans l'archive. *
* *
* Description : Ajoute un élement à une archive. *
* *
* Retour : Code de retour pour l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
CPError add_file_into_archive(struct archive *output, const char *filename, const char *path)
{
CPError result; /* Code de retour à renvoyer */
struct stat info; /* Informations d'origine */
int ret; /* Bilan d'un appel */
struct archive_entry *entry; /* Elément de l'archive */
int fd; /* Flux ouvert en lecture */
char buffer[ARCHIVE_RBUF_SIZE]; /* Tampon pour les transferts */
ssize_t len; /* Quantité de données lues */
result = CPE_ARCHIVE_ERROR;
ret = stat(filename, &info);
if (ret != 0)
{
perror("stat");
result = CPE_SYSTEM_ERROR;
goto afia_quick_exit;
}
entry = archive_entry_new();
archive_entry_copy_stat(entry, &info);
archive_entry_set_pathname(entry, path);
ret = archive_write_header(output, entry);
if (ret != 0) goto afia_exit;
fd = open(filename, O_RDONLY);
if (fd == -1)
{
perror("open");
result = CPE_SYSTEM_ERROR;
goto afia_exit;
}
for (len = safe_read_partial(fd, buffer, ARCHIVE_RBUF_SIZE);
len > 0;
len = safe_read_partial(fd, buffer, ARCHIVE_RBUF_SIZE))
{
if (archive_write_data(output, buffer, len) != len)
goto afia_exit;
}
close(fd);
archive_entry_free(entry);
return CPE_NO_ERROR;
afia_exit:
archive_entry_free(entry);
afia_quick_exit:
return result;
}
/******************************************************************************
* *
* Paramètres : intput = archive dont le contenu est à extraire. *
* entry = entrée de l'archive à extraire. *
* filename = chemin d'accès au fichier de sortie. *
* *
* Description : Extrait un élement d'une archive. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool dump_archive_entry_into_file(struct archive *input, struct archive_entry *entry, const char *filename)
{
bool result; /* Conclusion à retourner */
int flags; /* Propriétés à extraire */
struct archive *output; /* Extracteur générique */
int ret; /* Bilan d'un appel */
const void *buff; /* Tampon de copie */
size_t size; /* Quantité copiée */
__LA_INT64_T offset; /* Position de lecture */
result = false;
archive_entry_set_pathname(entry, filename);
/* Propriétés à restaurer */
flags = ARCHIVE_EXTRACT_TIME;
flags |= ARCHIVE_EXTRACT_PERM;
flags |= ARCHIVE_EXTRACT_ACL;
flags |= ARCHIVE_EXTRACT_FFLAGS;
output = archive_write_disk_new();
archive_write_disk_set_options(output, flags);
archive_write_disk_set_standard_lookup(output);
ret = archive_write_header(output, entry);
if (ret != ARCHIVE_OK) goto daeif_exit;
for (ret = archive_read_data_block(input, &buff, &size, &offset);
ret == ARCHIVE_OK;
ret = archive_read_data_block(input, &buff, &size, &offset))
{
ret = archive_write_data_block(output, buff, size, offset);
}
if (ret != ARCHIVE_EOF)
goto daeif_exit;
ret = archive_write_finish_entry(output);
result = (ret == ARCHIVE_OK);
daeif_exit:
archive_write_close(output);
archive_write_free(output);
return result;
}
/******************************************************************************
* *
* Paramètres : intput = archive dont le contenu est à extraire. *
* entry = entrée de l'archive à extraire. *
* *
* Description : Extrait un élement d'une archive. *
* *
* Retour : Nouveau contenu volatile ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
GBinContent *dump_archive_entry_into_memory(struct archive *input, struct archive_entry *entry)
{
GBinContent *result; /* Contenu à retourner */
bin_t *full_data; /* Données rassemblées */
phys_t full_size; /* Somme de toutes les tailles */
const void *buff; /* Tampon de copie */
size_t size; /* Quantité copiée */
__LA_INT64_T offset; /* Position de lecture */
int ret; /* Bilan d'un appel */
result = NULL;
full_data = NULL;
full_size = 0;
for (ret = archive_read_data_block(input, &buff, &size, &offset);
ret == ARCHIVE_OK;
ret = archive_read_data_block(input, &buff, &size, &offset))
{
full_data = realloc(full_data, full_size + size);
memcpy(full_data + full_size, buff, size);
full_size += size;
}
if (ret == ARCHIVE_EOF)
result = g_memory_content_new(full_data, full_size);
if (full_data != NULL)
free(full_data);
return result;
}