यदि गति महत्वपूर्ण है और संपीड़न की आवश्यकता नहीं है, तो आप हमारे द्वारा इसकी गणना करने के लिए बदलने के लिए tarउपयोग किए जाने वाले syscall रैपर को हुक कर सकते हैं। हमारी आवश्यकताओं के अनुरूप इन कार्यों में से कुछ को फिर से लागू करके (संभावित आउटपुट टार डेटा के आकार की गणना), हम बहुत कुछ खत्म करने में सक्षम हैं और जो सामान्य ऑपरेशन में किया जाता है । यह बहुत तेजी से बनाता है क्योंकि इसे संदर्भ में आगे और पीछे कर्नेल में कहीं भी स्विच करने की आवश्यकता नहीं होती है और केवल अनुरोधित इनपुट फ़ाइल / फ़ोल्डर (डिस्क) को वास्तविक फ़ाइल डेटा के बजाय डिस्क से पढ़ने की आवश्यकता होती है।LD_PRELOADtarreadwritetartarstat
नीचे दिए गए कोड के कार्यान्वयन में शामिल हैं close, readऔर writePOSIX कार्य करता है। मैक्रो OUT_FDकंट्रोल जो फाइल डिस्क्रिप्टर tarको आउटपुट फाइल के रूप में उपयोग करने की उम्मीद करते हैं। वर्तमान में यह stdout पर सेट है।
readकेवल countडेटा के साथ buf भरने के बजाय बाइट्स की सफलता का मूल्य वापस करने के लिए बदल दिया गया था , यह देखते हुए कि वास्तविक डेटा को buf नहीं पढ़ा गया था जिसमें संपीड़न पर गुजरने के लिए मान्य डेटा नहीं होगा, और इस प्रकार यदि संपीड़न का उपयोग किया गया था तो हम एक गलत गणना करेंगे। आकार।
writeइनपुट countबाइट्स को ग्लोबल वैरिएबल में समिट करने के लिए बदल दिया गया था totalऔर countबाइट्स के सक्सेस वैल्यू को तभी लौटाया जाता है, जब फाइल डिस्क्रिप्टर मैच करता है OUT_FD, अन्यथा यह dlsymउसी नाम के syscall को करने के लिए अधिग्रहीत मूल रैपर को कॉल करता है ।
closeअभी भी अपनी मूल कार्यक्षमता के बारे में सबकुछ बताता है, लेकिन यदि फाइल डिस्क्रिप्टर OUT_FD से मेल खाता है, तो यह जानता है कि tarएक टार फाइल लिखने का प्रयास किया जाता है, इसलिए यह totalसंख्या अंतिम है और यह इसे स्टडआउट करने के लिए प्रिंट करता है।
#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);
}
बेंचमार्क एक समाधान की तुलना करता है, जहां रीड डिस्क एक्सेस और सामान्य टार ऑपरेशन के सभी syscalls 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विकल्प के साथ चारों ओर खेल सकते हैं । किसी भी तरह से यदि आप डिस्क को भरते हैं तो आप केवल आर्काइव, इमो को हटा सकते हैं। उपलब्ध सभी विकल्पों की जांच करने के लिए आप इससे गुजर सकते हैंtar --help।