Si la vitesse est importante et que la compression n'est pas nécessaire, vous pouvez accrocher les wrappers syscall utilisés à l' taraide de LD_PRELOAD, pour les modifier taret les calculer pour nous. En réimplémentant quelques - unes de ces fonctions pour répondre à nos besoins (calcul de la taille des données de goudron de la production potentielle), nous sommes en mesure d' éliminer beaucoup de readet writequi est effectué en fonctionnement normal tar. Cela rend tarbeaucoup plus rapide car il n'a pas besoin de basculer le contexte d'avant en arrière dans le noyau à peu près autant et seul le statfichier / dossier d'entrée requis doit être lu à partir du disque au lieu des données de fichier réelles.
Le code ci - dessous comprend les mises en œuvre des close, readet des writefonctions POSIX. La macro OUT_FDcontrôle le descripteur de fichier que nous prévoyons tard'utiliser comme fichier de sortie. Actuellement, il est défini sur stdout.
reada été modifié pour renvoyer simplement la valeur de succès des countoctets au lieu de remplir buf avec les données, étant donné que les données réelles n'ont pas été lues buf ne contiendrait pas de données valides pour passer à la compression, et donc si la compression était utilisée, nous calculerions une erreur Taille.
writea été modifié pour additionner les countoctets d' entrée dans la variable globale totalet renvoyer la valeur de succès des countoctets uniquement si le descripteur de fichier correspond OUT_FD, sinon il appelle l'encapsuleur d'origine acquis via dlsympour effectuer l'appel système du même nom.
closepréforme toujours toutes ses fonctionnalités d'origine, mais si le descripteur de fichier correspond à OUT_FD, il sait que cela tarest fait en essayant d'écrire un fichier tar, donc le totalnombre est final et il l'imprime sur stdout.
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h>
#include <errno.h>
#include <dlfcn.h>
#include <string.h>
#define OUT_FD 1
uint64_t total = 0;
ssize_t (*original_write)(int, const void *, size_t) = NULL;
int (*original_close)(int) = NULL;
void print_total(void)
{
printf("%" PRIu64 "\n", total);
}
int close(int fd)
{
if(! original_close)
{
original_close = dlsym(RTLD_NEXT, "close");
}
if(fd == OUT_FD)
{
print_total();
}
return original_close(fd);
}
ssize_t read(int fd, void *buf, size_t count)
{
return count;
}
ssize_t write(int fd, const void *buf, size_t count)
{
if(!original_write)
{
original_write = dlsym(RTLD_NEXT, "write");
}
if(fd == OUT_FD)
{
total += count;
return count;
}
return original_write(fd, buf, count);
}
Benchmark comparant une solution où l'accès au disque de lecture et tous les appels système de l'opération tar normale sont effectués par rapport à la LD_PRELOADsolution.
$ time tar -c /media/storage/music/Macintosh\ Plus-\ Floral\ Shoppe\ \(2011\)\ \[Flac\]/ | wc -c
332308480
real 0m0.457s
user 0m0.064s
sys 0m0.772s
tarsize$ time ./tarsize.sh -c /media/storage/music/Macintosh\ Plus-\ Floral\ Shoppe\ \(2011\)\ \[Flac\]/
332308480
real 0m0.016s
user 0m0.004s
sys 0m0.008s
Le code ci-dessus, un script de construction de base pour construire ce qui précède en tant que bibliothèque partagée et un script avec la " LD_PRELOADtechnique" l'utilisant sont fournis dans le référentiel:
https://github.com/G4Vi/tarsize
Quelques informations sur l'utilisation de LD_PRELOAD: https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/
--totalsoption. Quoi qu'il en soit, si vous remplissez le disque, vous pouvez simplement supprimer l'archive, à mon humble avis. Pour vérifier toutes les options disponibles, vous pouvez passer partar --help.