Se la velocità è importante e la compressione non è necessaria, è possibile agganciare i wrapper syscall utilizzati tarutilizzando LD_PRELOAD, per modificare tarper calcolarlo per noi. Reimplementando alcune di queste funzioni per soddisfare le nostre esigenze (calcolando la dimensione dei potenziali dati di catrame di output), siamo in grado di eliminare molte reade writeche vengono eseguite nel normale funzionamento di tar. Questo fatar molto più veloce in quanto non ha bisogno di passare da un contesto all'altro nel kernel in qualsiasi punto vicino e solo il statfile / le cartelle di input richiesto deve essere letto dal disco invece dei dati del file effettivo.
Il codice sotto include implementazioni dei close, reade writefunzioni POSIX. La macro OUT_FDcontrolla quale descrittore di file ci aspettiamotar di utilizzare come file di output. Attualmente è impostato su stdout.
readè stato modificato per restituire semplicemente il valore di successo dei countbyte invece di riempire buf con i dati, dato che i dati effettivi non sono stati letti buf non conterrebbero dati validi per il passaggio alla compressione, quindi se si utilizzava la compressione calcoleremmo un errore dimensione.
writeè stato modificato per sommare i countbyte di input nella variabile globale totale restituire il valore di successo dei countbyte solo se il descrittore di file corrisponde OUT_FD, altrimenti chiama il wrapper originale acquisito tramitedlsym per eseguire la syscall con lo stesso nome.
closepreforma ancora tutte le sue funzionalità originali, ma se il descrittore di file corrisponde a OUT_FD, sa che tarsi tenta di scrivere un file tar, quindi il totalnumero è definitivo e lo stampa su 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 confrontando una soluzione in cui l'accesso al disco di lettura e tutte le syscall della normale operazione tar vengono eseguiti rispetto alla LD_PRELOADsoluzione.
$ 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
Il codice sopra, uno script di compilazione di base per creare quanto sopra come libreria condivisa e uno script con la " LD_PRELOADtecnica" che lo utilizza viene fornito nel repository:
https://github.com/G4Vi/tarsize
Alcune informazioni sull'uso di LD_PRELOAD: https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/
--totalsopzione. In ogni caso, se riempi il disco, puoi semplicemente eliminare l'archivio, imho. Per verificare tutte le opzioni disponibili è possibile passare attraversotar --help.