Como exibir as partes não esparsas de um arquivo esparso?

8

Imagine um arquivo criado com:

truncate -s1T file
echo test >> file
truncate -s2T file

Agora eu tenho um arquivo de 2 tebibytes (que ocupa 4kiB no disco), com "test\n"escrito no meio.

Como eu recuperaria isso com "test"eficiência, ou seja, sem ter que ler o arquivo inteiro.

tr -d '\0' < file

Me daria o resultado, mas isso levaria horas.

O que eu gostaria é algo que produz apenas as partes não esparsas do arquivo (tão acima apenas "test\n"ou mais provavelmente, o bloco 4kiB alocado no disco que armazena esses dados).

Existem APIs para descobrir qual parte do arquivo está alocada (FIBMAP, FIEMAP, SEEK_HOLE, SEEK_DATA ...), mas que ferramentas as expõem?

Uma solução portátil (pelo menos para os sistemas operacionais que suportam essas APIs) seria apreciada.

Stéphane Chazelas
fonte
Quão eficiente é strings?
Glenn Jackman
@glennjackman, menos do que trporque ainda lê o arquivo inteiro e faz mais do que apenas remover os bytes NUL.
Stéphane Chazelas 26/03

Respostas:

6

O melhor que pude apresentar até agora é (ksh93, usando a filefragpartir de e2fsprogs1.42.9 (algumas versões mais antigas têm uma API diferente), em sistemas de arquivos baseados em extensão no Linux):

#! /bin/ksh93
export LC_ALL=C
for file do
filefrag -vb1 -- "$file" |
  while IFS=": ." read -A a; do
    [[ $a = +([0-9]) ]] && [[ ${a[@]} != *unwritten* ]] &&
      command /opt/ast/bin/head -s "${a[1]}" -c "${a[7]}" -- "$file"
  done
done

filefrag relata as extensões do arquivo usando o FIEMAP ioctl para os sistemas de arquivos que o suportam.

A *unwritten*parte cobre os arquivos (não esparsos, mas ainda cheios de zeros nos quais não estou interessado) que foram fallocatedmas não foram gravados.

Versões recentes bsdtarou starpodem usar algumas dessas APIs para gerar um tararquivo que identifica as seções esparsas como tais. Isso tornaria uma solução mais portátil , mas seria necessário analisar o arquivo tar gerado para obter as seções não esparsas.

Stéphane Chazelas
fonte