Wenn Geschwindigkeit wichtig ist und keine Komprimierung erforderlich ist, können Sie die verwendeten Syscall-Wrapper tar
mit 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 read
und write
dass im Normalbetrieb von ausgeführt tar
. Dies macht es tar
viel schneller, da der Kontext nicht annähernd so schnell in den Kernel gewechselt werden muss und stat
statt der eigentlichen Dateidaten nur die angeforderten Eingabedateien / -ordner von der Festplatte gelesen werden müssen.
Der folgende Code enthält Implementierungen der close
, read
und write
POSIX - Funktionen. Das Makro OUT_FD
steuert, welcher Dateideskriptor tar
als Ausgabedatei verwendet werden soll. Derzeit ist es auf stdout eingestellt.
read
wurde so geändert, dass nur der Erfolgswert von count
Bytes 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.
write
wurde geändert, um die Eingabebytes count
in die globale Variable zu summieren total
und den Erfolgswert von count
Bytes nur dann zurückzugeben, wenn der Dateideskriptor übereinstimmt OUT_FD
. Andernfalls wird der ursprüngliche Wrapper dlsym
aufgerufen, der über erworben wurde , um den gleichnamigen Syscall auszuführen.
close
Die ursprüngliche Funktionalität bleibt erhalten, aber wenn der Dateideskriptor mit OUT_FD übereinstimmt, tar
wird versucht, eine tar-Datei zu schreiben. Die total
Zahl 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_PRELOAD
Lö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_PRELOAD
Technik", 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/
--totals
Option 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
.