Якщо швидкість важлива, а компресія не потрібна, ви можете підключити обгортки syscall, використовувані за tarдопомогою LD_PRELOAD, щоб змінити, tarщоб обчислити її для нас. Перевизначення деякі з цих функцій , щоб задовольнити наші потреби (розрахунок розміру потенційного виведення даних гудрону), ми можемо виключити багато readі writeщо виконується при нормальній роботі tar. Це робиться tarнабагато швидше, оскільки не потрібно перемикання контексту вперед і назад в ядро в будь-якому місці, і тільки statз потрібного вхідного файлу / папки (файлів) потрібно читати з диска замість фактичних даних про файл.
Нижче код включає в себе варіанти реалізації close, readі writeфункції POSIX. Макрос OUT_FDконтролює дескриптор файлу, який ми очікуємо tarвикористовувати як вихідний файл. В даний час він встановлений на stdout.
readбуло змінено, щоб просто повернути значення успішності countбайтів замість заповнення buf даними, враховуючи, що фактичні дані не були прочитані. Буф не містив би дійсних даних для переходу до стиснення, і, таким чином, якщо було використано стиснення, ми обчислимо неправильне розмір.
writeбуло змінено для підсумовування вхідних countбайтів у глобальну змінну totalта повернення значення успішності countбайтів, лише якщо дескриптор файлу збігається OUT_FD, інакше він викликає оригінальну обгортку, придбану через, dlsymщоб виконати однойменну системну виклик.
closeвсе ще заздалегідь виконує всі свої оригінальні функціональні можливості, але якщо дескриптор файлу відповідає OUT_FD, він знає, що tarробиться спроба написати файл tar, тому totalчисло остаточне, і він виводить його на 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);
}
Бенчмарк порівняння рішення, де доступ до зчитуваного диска та всі системні виклики нормальної роботи тарінгу виконуються проти LD_PRELOADрішення.
$ 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
Код вище, базовий сценарій збірки будувати вище , в якості загальної бібліотеки, і сценарій з « LD_PRELOADтехнікою» , використовуючи його надаються в репо:
https://github.com/G4Vi/tarsize
Деякі відомості про використання LD_PRELOAD: https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/
--totalsопцією. У будь-якому випадку, якщо ви заповнили диск, ви можете просто видалити архів, imho. Щоб перевірити всі наявні варіанти, які ви могли пройтиtar --help.