Se a velocidade for importante e a compactação não for necessária, você pode conectar os wrappers syscall usados tarusando LD_PRELOAD, para alterar tarpara 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 reade writeisso é realizado na operação normal de tar. Isso fica tarmuito mais rápido, pois não é necessário alternar o contexto para o kernel em qualquer lugar próximo e somente o statarquivo / 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, reade writefunções POSIX. A macro OUT_FDcontrola qual descritor de arquivo esperamos tarusar como arquivo de saída. Atualmente, está definido como stdout.
readfoi alterado para apenas retornar o valor de sucesso dos countbytes 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.
writefoi alterado para somar os countbytes de entrada na variável global totale retornar o valor de sucesso dos countbytes apenas se o descritor de arquivo corresponder OUT_FD; caso contrário, ele chamará o wrapper original adquirido via dlsympara executar a chamada do sistema com o mesmo nome.
closeainda pré-forma toda a sua funcionalidade original, mas se o descritor de arquivo corresponder a OUT_FD, ele saberá que isso tarfoi feito ao tentar gravar um arquivo tar; portanto, o totalnú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_PRELOADsoluçã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_PRELOADté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/
--totalsopçã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.