Nếu tốc độ là quan trọng và không cần nén, bạn có thể móc các hàm bao của tòa nhà được sử dụng bằng tar
cách sử dụng LD_PRELOAD
, để thay đổi tar
để tính toán cho chúng tôi. Bằng cách thực hiện lại một vài trong số các chức năng này để phù hợp với nhu cầu của chúng tôi (tính toán kích thước của dữ liệu tar đầu ra tiềm năng), chúng tôi có thể loại bỏ rất nhiều read
và write
điều đó được thực hiện trong hoạt động bình thường tar
. Điều này làm cho tar
nhanh hơn nhiều vì nó không cần phải chuyển ngữ cảnh qua lại vào kernel ở bất kỳ đâu gần như và chỉ stat
cần đọc (các) tệp / thư mục đầu vào được yêu cầu từ đĩa thay vì dữ liệu tệp thực tế.
Đoạn code dưới đây bao gồm việc triển khai của close
, read
và write
các chức năng POSIX. Macro OUT_FD
kiểm soát mô tả tệp mà chúng tôi dự kiến tar
sẽ sử dụng làm tệp đầu ra. Hiện tại nó được đặt thành thiết bị xuất chuẩn.
read
đã được thay đổi thành chỉ trả về giá trị thành công của count
byte thay vì điền dữ liệu vào buf, với điều kiện là dữ liệu thực tế không được đọc buf sẽ không chứa dữ liệu hợp lệ để chuyển sang nén và do đó, nếu sử dụng nén, chúng tôi sẽ tính toán không chính xác kích thước.
write
được thay đổi để tổng hợp các đầu vào count
byte vào biến toàn cầu total
và trả về giá trị thành công của count
byte chỉ nếu trận mô tả tập tin OUT_FD
, nếu không nó gọi wrapper gốc mua qua dlsym
để thực hiện các syscall cùng tên.
close
vẫn tạo ra tất cả các chức năng ban đầu của nó, nhưng nếu bộ mô tả tệp khớp với OUT_FD, nó biết rằng đã tar
hoàn thành việc cố gắng ghi một tệp tar, vì vậy total
số này là cuối cùng và nó in ra thiết bị xuất chuẩn.
#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);
}
Điểm chuẩn so sánh một giải pháp trong đó truy cập đĩa đọc và tất cả các tòa nhà của hoạt động tar bình thường được thực hiện đối với LD_PRELOAD
giải pháp.
$ 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
Mã ở trên, tập lệnh xây dựng cơ bản để xây dựng ở trên dưới dạng thư viện dùng chung và tập lệnh có " LD_PRELOAD
kỹ thuật" sử dụng được cung cấp trong repo:
https://github.com/G4Vi/tarsize
Một số thông tin về việc sử dụng LD_PRELOAD: https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-USE-ld_preload-to-cheat-inject-features-and-investigate-programs/
--totals
tùy chọn. Dù bằng cách nào, nếu bạn lấp đầy đĩa, bạn chỉ cần xóa kho lưu trữ, imho. Để kiểm tra tất cả các tùy chọn có sẵn, bạn có thể đi quatar --help
.