Se a velocidade for importante e a compactação não for necessária, você pode conectar os wrappers syscall usados tar
usando LD_PRELOAD
, para alterar tar
para calculá-lo para nós. Reimplementando algumas dessas funções para atender às nossas necessidades (calculando o tamanho dos possíveis dados do alcatrão de saída), somos capazes de eliminar muito read
e write
isso é realizado na operação normal de tar
. Isso fica tar
muito mais rápido, pois não é necessário alternar o contexto para o kernel em qualquer lugar próximo e somente o stat
arquivo / pasta de entrada solicitados precisa ser lido do disco em vez dos dados reais do arquivo.
O código abaixo inclui implementações das close
, read
e write
funções POSIX. A macro OUT_FD
controla qual descritor de arquivo esperamos tar
usar como arquivo de saída. Atualmente, está definido como stdout.
read
foi alterado para apenas retornar o valor de sucesso dos count
bytes em vez de preencher o buf com os dados, dado que os dados reais não foram lidos, o buf não conteria dados válidos para transmitir à compactação e, portanto, se a compactação fosse usada, calcularíamos um valor incorreto Tamanho.
write
foi alterado para somar os count
bytes de entrada na variável global total
e retornar o valor de sucesso dos count
bytes apenas se o descritor de arquivo corresponder OUT_FD
; caso contrário, ele chamará o wrapper original adquirido via dlsym
para executar a chamada do sistema com o mesmo nome.
close
ainda pré-forma toda a sua funcionalidade original, mas se o descritor de arquivo corresponder a OUT_FD, ele saberá que isso tar
foi feito ao tentar gravar um arquivo tar; portanto, o total
número é final e o imprime em 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);
}
Referência comparando uma solução em que o acesso ao disco de leitura e todos os syscalls da operação tar normal são executados na LD_PRELOAD
solução.
$ 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
O código acima, um script de construção básico para criar o descrito acima como uma biblioteca compartilhada, e um script com a " LD_PRELOAD
técnica" que o utiliza são fornecidos no repositório:
https://github.com/G4Vi/tarsize
Algumas informações sobre o uso do LD_PRELOAD: https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/
--totals
opção De qualquer maneira, se você encher o disco, você pode simplesmente excluir o arquivo, imho. Para verificar todas as opções disponíveis, você pode acessartar --help
.