Hız önemlidir ve sıkıştırma gerekli değilse, sen kullandığı syscall sarmalayıcılarını kanca tar
kullanarak LD_PRELOAD
değiştirmek, tar
bizim 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 read
ve write
bu normal çalışmasında gerçekleştirilir tar
. Bu tar
bağlamda çekirdeğe ileri ve geri çevrilmesi gerekmediği için çok daha hızlı hale gelir stat
ve istenen dosya / klasörlerin sadece istenen dosya verileri yerine diskten okunması gerekir.
Aşağıdaki kod uygulamalarını içerir close
, read
ve write
POSIX işlevleri. Makro , çıktı dosyası olarak OUT_FD
hangi dosya tanımlayıcısını tar
kullanacağımızı kontrol eder . Şu anda stdout olarak ayarlanmış.
read
count
gerç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.
write
giriş count
baytlarını global değişkene toplamak ve sadece dosya tanımlayıcısı eşleşirse baytların total
baş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 .count
OUT_FD
dlsym
close
hala orijinal işlevlerinin tamamını hazırlar, ancak dosya tanımlayıcısı OUT_FD ile eşleşiyorsa, bunun tar
bir tar dosyası yazmaya çalışıldığını bilir , bu nedenle total
sayı 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_PRELOAD
tekniğ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/
--totals
seçenekle oynayabilirsiniz . Her iki durumda da, diski doldurursanız, arşivi silebilirsiniz, yani. Mevcut tüm seçenekleri kontrol etmek için gidebilirsiniztar --help
.