Como faço para remover todas as lacunas em um arquivo esparso no Linux? No Windows, acredito que o procedimento seja
fsutil sparse setflag <file> 0
Qual é o equivalente do Linux?
(Eu sei cp <file> <file>.cp; rm <file>; mv <file>.cp <file>;
que daria conta do recado, se o espaço livre em disco permitir, mas acho que o Linux tem uma maneira local de fazer isso? Como o Windows?)
fallocate -l <length> <file>
poderia conseguir isso; embora não diga ao sistema de arquivos para preencher explicitamente os buracos, ele aloca espaço para eles. Compare com:Use
filefrag -v <file>
ouxfs_io -r -c "fiemap -v" <file>
para listar as extensões de um arquivo. Neste exemplo, após falocar não há mais buracos propriamente ditos; eles agora estão cobertos por extensões 'não escritas' nas quais o sistema de arquivos continuará retornando zeros imediatamente na leitura, mas que agora possuem blocos físicos específicos atribuídos a eles.Seria tecnicamente possível adicionar uma opção de fallocate que usa FIEMAP para listar buracos e/ou extensões "não escritas" e preenchê-los com zero, mas infelizmente não tem uma no momento e requer o deslocamento/comprimento de preenchimento com zero ser especificado manualmente.
Se o arquivo ficar truncado entre o
stat -c %s
e ofallocate
, a última operação irá aumentá-lo novamente para o tamanho anterior.Você pode evitar isso usando
-n/--keep-size
(que apenas pré-aloca espaço, mas não aumenta o arquivo) se espera que ele cresça novamente, embora a semântica exata do Linux para alocar espaço além do EOF não seja um pouco clara para mim. (Suponho que seja semelhante ao 'arquivo fsutil setEOF/setValidData' do Windows.)Por outro lado, se o arquivo crescer entre as duas operações, não será truncado; os dados (ou buracos) recém-adicionados simplesmente não serão afetados pela falocate. (Ou seja, você não perderá nenhum dado; na pior das hipóteses, você só precisará fazer isso novamente para se livrar dos buracos recém-adicionados.)
Tenha cuidado com
cp
– nas versões recentes do GNU Coreutils, ele tentará automaticamente preservar a dispersão usando SEEK_HOLE. Pode ser necessário usarcp --sparse=never
para evitar isso.Além disso, a partir do Coreutils 9.x,
cp foo bar
e atécat foo > bar
usará automaticamente as operações FICLONE ou copy_file_range() para clonar arquivos sem realmente copiar seus dados se o sistema de arquivos suportar isso, por exemplo, em XFS ou Btrfs ou ZFS (semelhante ao "block cloning "recurso no ReFS).Se isso acontecer, a "cópia" manterá exatamente a dispersão original do arquivo e você verá o
shared
sinalizador para cada extensão na saída do filefrag. Você pode usarcp --reflink=never
para evitar isso.(Há um sinalizador para a chamada do sistema fallocate para cancelar o compartilhamento de extensões, mas ele ainda não foi exposto por meio da
fallocate
ferramenta de linha de comando, embora você possa fazer isso por meioxfs_io
do subcomando 'funshare'.)