Якщо швидкість важлива, а компресія не потрібна, ви можете підключити обгортки 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
.