속도가 중요하고 압축이 필요하지 않은 경우을 사용 tar
하여 사용 된 syscall 랩퍼를 후크하여 계산 LD_PRELOAD
하도록 변경할 tar
수 있습니다. 잠재적 인 출력 타르 데이터의 크기를 계산하는 우리의 요구에 맞게 이러한 기능 중 일부를 다시 구현함으로써 많은 작업을 제거 할 수 read
있으며 write
이는 정상 작동시 수행됩니다 tar
. 이것은 tar
컨텍스트에서 커널로 앞뒤로 전환 할 필요가 없기 때문에 훨씬 빠릅니다.stat
요청 된 입력 파일 / 폴더 만 실제 파일 데이터 대신 디스크에서 읽어야하기 .
아래의 코드는 구현 포함 close
, read
및 write
POSIX 기능. 매크로 OUT_FD
는 tar
출력 파일로 사용할 파일 설명자를 제어 합니다. 현재는 표준 출력으로 설정되어 있습니다.
read
count
실제 데이터를 읽지 않은 경우 buf에 데이터를 채우지 않고 바이트 의 성공 값을 반환하도록 변경되었습니다. buf는 압축으로 전달하기위한 유효한 데이터를 포함하지 않으므로 압축을 사용하면 잘못된 값을 계산합니다 크기.
write
입력 count
바이트를 전역 변수 에 합산하고 파일 디스크립터가 일치하는 경우 에만 바이트 total
의 성공 값을 리턴하도록 변경되었습니다 . 그렇지 않으면 동일한 이름의 syscall을 수행하기 위해 획득 한 원래 랩퍼를 호출합니다 .count
OUT_FD
dlsym
close
여전히 원래 기능을 모두 수행하지만 파일 디스크립터가 OUT_FD와 일치 tar
하면 tar 파일을 작성하려고 시도한 것으로 알고 있으므로 total
숫자가 최종이고 stdout에 인쇄합니다.
#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);
}
읽기 디스크 액세스 및 일반 tar 조작의 모든 시스템 호출이 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
옵션으로 재생할 수 있습니다 . 어느 쪽이든 디스크를 채우면 간단히 아카이브를 삭제할 수 있습니다 (imho). 사용 가능한 모든 옵션을 확인하려면를 수행하십시오tar --help
.