Wenn Geschwindigkeit wichtig ist und keine Komprimierung erforderlich ist, können Sie die verwendeten Syscall-Wrapper tarmit LD_PRELOAD, ändern tar, um sie für uns zu berechnen. Durch einige dieser Funktionen neu implementieren unsere Bedürfnisse anzupassen (die Größe der möglichen Ausgangs tar Daten Berechnung), sind wir viel beseitigen können readund writedass im Normalbetrieb von ausgeführt tar. Dies macht es tarviel schneller, da der Kontext nicht annähernd so schnell in den Kernel gewechselt werden muss und statstatt der eigentlichen Dateidaten nur die angeforderten Eingabedateien / -ordner von der Festplatte gelesen werden müssen.
Der folgende Code enthält Implementierungen der close, readund writePOSIX - Funktionen. Das Makro OUT_FDsteuert, welcher Dateideskriptor tarals Ausgabedatei verwendet werden soll. Derzeit ist es auf stdout eingestellt.
readwurde so geändert, dass nur der Erfolgswert von countBytes zurückgegeben wird, anstatt buf mit den Daten zu füllen, da die tatsächlichen Daten nicht gelesen wurden. buf würde keine gültigen Daten für die Weitergabe an die Komprimierung enthalten. Wenn also die Komprimierung verwendet würde, würden wir einen falschen Wert berechnen Größe.
writewurde geändert, um die Eingabebytes countin die globale Variable zu summieren totalund den Erfolgswert von countBytes nur dann zurückzugeben, wenn der Dateideskriptor übereinstimmt OUT_FD. Andernfalls wird der ursprüngliche Wrapper dlsymaufgerufen, der über erworben wurde , um den gleichnamigen Syscall auszuführen.
closeDie ursprüngliche Funktionalität bleibt erhalten, aber wenn der Dateideskriptor mit OUT_FD übereinstimmt, tarwird versucht, eine tar-Datei zu schreiben. Die totalZahl ist also endgültig und wird auf stdout gedruckt.
#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-Vergleich einer Lösung, bei der der Lesezugriff auf die Festplatte und alle Systemaufrufe des normalen Tar-Vorgangs mit der LD_PRELOADLösung durchgeführt werden.
$ 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
Der obige Code, ein grundlegendes Erstellungsskript, um das Obige als gemeinsam genutzte Bibliothek zu erstellen, und ein Skript mit der " LD_PRELOADTechnik", die es verwendet, sind im Repository enthalten:
https://github.com/G4Vi/tarsize
Einige Informationen zur Verwendung von LD_PRELOAD: https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/
--totalsOption herumspielen. In beiden Fällen können Sie das Archiv einfach löschen, wenn Sie die Festplatte voll haben. Um alle verfügbaren Optionen zu überprüfen, können Sie durchgehentar --help.