Em face disso, é um simples dd
:
dd if=sparsefile of=sparsefile conv=notrunc bs=1M
Isso lê o arquivo inteiro e grava todo o conteúdo nele.
Para escrever apenas o furo, você primeiro precisa determinar onde estão esses buracos. Você pode fazer isso usando filefrag
ou hdparm
:
filefrag:
# filefrag -e sparsefile
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 1048575: 187357696.. 188406271: 1048576:
1: 1572864.. 2621439: 200704128.. 201752703: 1048576: 188406272: last,eof
sparsefile: 2 extents found
hdparm:
# hdparm --fibmap sparsefile
sparsefile:
filesystem blocksize 4096, begins at LBA 0; assuming 512 byte sectors.
byte_offset begin_LBA end_LBA sectors
0 1498861568 1507250175 8388608
6442450944 1605633024 1614021631 8388608
Este arquivo de exemplo é, como você diz, 10G
em tamanho com um 2G
hole. Ele tem duas extensões, a primeira cobrindo 0-1048575
, a segunda 1572864-2621439
, o que significa que o furo é 1048576-1572864
(em blocos de tamanho 4k, como mostrado por filefrag
). As informações mostradas por hdparm
são as mesmas, apenas exibidas de forma diferente (a primeira extensão abrange 8388608
setores de 512 bytes começando por 0, então é 0-4294967295
bytes, portanto, o furo é 4294967296-6442450944
em bytes.
Note que você pode ser mostrado consideravelmente mais extensões de qualquer maneira, se houver alguma fragmentação. Infelizmente, nenhum dos comandos mostra os buracos diretamente, e eu não conheço um que faça isso, então você deve deduzi-lo das compensações lógicas mostradas.
Agora, preencher esse 1048576-1572864
com dd
, como mostrado acima, pode ser feito adicionando valores% (%)seek
/ skip
(%) e count
apropriados (idênticos). Observe que o bs=
foi adaptado para usar os 4k
setores usados por filefrag
acima. (Para bs=1M
, você teria que adaptar os valores de seek / skip / count para refletir os blocos 1M
sized).
dd if=sparsefile of=sparsefile conv=notrunc \
bs=4k seek=1048576 skip=1048576 count=$((-1048576+1572864))
Embora você possa preencher furos com /dev/zero
em vez de ler o furo do arquivo em si (que também renderá zeros), é mais seguro ler o sparsefile
de qualquer maneira, para que você não corrompa seus dados caso você tenha um deslocamento errado.
Nas versões mais recentes de GNU dd
, você pode manter um tamanho maior de blocos e especificar todos os valores em bytes:
dd if=sparsefile of=sparsefile conv=notrunc bs=1M \
iflag=skip_bytes,count_bytes oflag=seek_bytes \
seek=4294967296 skip=4294967296 count=$((-4294967296+6442450944))
filefrag
depois de executar isso:
# sync
# filefrag -e sparsefile
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 1572863: 187357696.. 188930559: 1572864:
1: 1572864.. 2621439: 200704128.. 201752703: 1048576: 188930560: last,eof
sparsefile: 2 extents found
Devido à fragmentação, ainda são duas extensões. No entanto, as compensações lógicas mostram que, desta vez, não há nenhum furo, portanto, o arquivo não é mais esparso.
Naturalmente, essa solução dd
é a abordagem muito manual das coisas. Se você precisar disso regularmente, seria fácil escrever um pequeno programa que preenche essas lacunas. Se já existe como uma ferramenta padrão, ainda não ouvi falar disso.
Existe uma ferramenta, afinal, fallocate
parece funcionar, de certa forma:
fallocate -l $(stat --format="%s" sparsefile) sparsefile
No entanto, por fim, no caso do XFS, enquanto ele aloca área física para esse arquivo, ele não é zerado. filefrag
mostra extensões como alocadas, mas não escritas.
2: 3.. 15: 7628851.. 7628863: 13: 7629020: unwritten
Isso não é suficiente se a intenção for ler os dados corretos diretamente do dispositivo de bloco. Apenas reserva o espaço de armazenamento necessário para gravações futuras.