यदि गति महत्वपूर्ण है और संपीड़न की आवश्यकता नहीं है, तो आप हमारे द्वारा इसकी गणना करने के लिए बदलने के लिए tar
उपयोग किए जाने वाले syscall रैपर को हुक कर सकते हैं। हमारी आवश्यकताओं के अनुरूप इन कार्यों में से कुछ को फिर से लागू करके (संभावित आउटपुट टार डेटा के आकार की गणना), हम बहुत कुछ खत्म करने में सक्षम हैं और जो सामान्य ऑपरेशन में किया जाता है । यह बहुत तेजी से बनाता है क्योंकि इसे संदर्भ में आगे और पीछे कर्नेल में कहीं भी स्विच करने की आवश्यकता नहीं होती है और केवल अनुरोधित इनपुट फ़ाइल / फ़ोल्डर (डिस्क) को वास्तविक फ़ाइल डेटा के बजाय डिस्क से पढ़ने की आवश्यकता होती है।LD_PRELOAD
tar
read
write
tar
tar
stat
नीचे दिए गए कोड के कार्यान्वयन में शामिल हैं close
, read
और write
POSIX कार्य करता है। मैक्रो 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
।