Hız önemlidir ve sıkıştırma gerekli değilse, sen kullandığı syscall sarmalayıcılarını kanca tarkullanarak LD_PRELOADdeğiştirmek, tarbizim için hesaplamak için. Bu fonksiyonlardan bir kaçını ihtiyacımıza uyacak şekilde yeniden uygulayarak (potansiyel çıktı katran verilerinin boyutunu hesaplayarak), birçoğunu ortadan kaldırabiliriz readve writebu normal çalışmasında gerçekleştirilir tar. Bu tarbağlamda çekirdeğe ileri ve geri çevrilmesi gerekmediği için çok daha hızlı hale gelir statve istenen dosya / klasörlerin sadece istenen dosya verileri yerine diskten okunması gerekir.
Aşağıdaki kod uygulamalarını içerir close, readve writePOSIX işlevleri. Makro , çıktı dosyası olarak OUT_FDhangi dosya tanımlayıcısını tarkullanacağımızı kontrol eder . Şu anda stdout olarak ayarlanmış.
readcountgerçek veriyi okumayan buf sıkıştırmaya geçmek için geçerli veri içermeyeceği göz önüne alındığında, veriyi buf ile veriyi doldurmak yerine yalnızca bayt başarı değerini döndürmek için değiştirildi ve bu nedenle sıkıştırma kullanılırsa yanlış hesaplardık boyut.
writegiriş countbaytlarını global değişkene toplamak ve sadece dosya tanımlayıcısı eşleşirse baytların totalbaşarı değerini döndürmek için değiştirildi , aksi takdirde aynı adın çağrısını gerçekleştirmek için elde edilen orijinal sarmalayıcıyı çağırır .countOUT_FDdlsym
closehala orijinal işlevlerinin tamamını hazırlar, ancak dosya tanımlayıcısı OUT_FD ile eşleşiyorsa, bunun tarbir tar dosyası yazmaya çalışıldığını bilir , bu nedenle totalsayı kesindir ve stdout'a yazdırır.
#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);
}
Okunan diske erişimin ve normal katran işleminin tüm sistem çağrılarının LD_PRELOADçözüme karşı gerçekleştirildiği bir çözümü karşılaştıran kıyaslama .
$ 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
Yukarıdaki kod, yukarıdakileri paylaşılan bir kütüphane olarak oluşturmak için temel bir derleme betiği ve repo'da " LD_PRELOADtekniği" olan bir betik verilmiştir:
https://github.com/G4Vi/tarsize
LD_PRELOAD'ı kullanmayla ilgili bazı bilgiler: https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/
--totalsseçenekle oynayabilirsiniz . Her iki durumda da, diski doldurursanız, arşivi silebilirsiniz, yani. Mevcut tüm seçenekleri kontrol etmek için gidebilirsiniztar --help.