À première vue, c'est simple dd
:
dd if=sparsefile of=sparsefile conv=notrunc bs=1M
Cela lit l'intégralité du fichier et y réécrit l'intégralité du contenu.
Afin d'écrire uniquement le trou lui-même, vous devez d'abord déterminer où se trouvent ces trous. Vous pouvez le faire en utilisant soit 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
Cet exemple de fichier est, comme vous le dites, 10G
de taille avec un 2G
trou. Il a deux étendues, la première couvrant 0-1048575
, la seconde 1572864-2621439
, ce qui signifie que le trou est 1048576-1572864
(en blocs de taille 4k, comme indiqué par filefrag
). Les informations affichées par hdparm
sont les mêmes, juste affichées différemment (la première étendue couvre les 8388608
secteurs de 512 octets à partir de 0, donc ce sont des 0-4294967295
octets, donc le trou est 4294967296-6442450944
en octets.
Notez que vous pouvez de toute façon afficher beaucoup plus d'étendue en cas de fragmentation. Malheureusement, aucune des commandes n'affiche directement les trous, et je n'en connais aucun qui le fasse, vous devez donc le déduire des décalages logiques indiqués.
Maintenant, remplir ce 1048576-1572864
trou avec dd
comme indiqué ci-dessus, peut être fait en ajoutant des valeurs seek
/ ( skip
et ) appropriées (identiques) count
. Notez que le a bs=
été adapté pour utiliser les 4k
secteurs tels qu'utilisés filefrag
ci-dessus. (Pour bs=1M
, vous devez adapter les valeurs de recherche / saut / comptage pour refléter 1M
les blocs de taille).
dd if=sparsefile of=sparsefile conv=notrunc \
bs=4k seek=1048576 skip=1048576 count=$((-1048576+1572864))
Bien que vous puissiez remplir des trous au /dev/zero
lieu de lire le trou du fichier lui-même (ce qui ne fera que générer des zéros), il est plus sûr de lire de sparsefile
toute façon afin de ne pas corrompre vos données au cas où un décalage serait incorrect.
Dans les versions plus récentes de GNU dd
, vous pouvez vous en tenir à une taille de bloc plus grande et spécifier toutes les valeurs en octets:
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
après avoir exécuté cela:
# 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
En raison de la fragmentation, il s'agit toujours de deux extensions. Cependant, les décalages logiques montrent que cette fois, il n'y a pas de trou, donc le fichier n'est plus clairsemé.
Naturellement, cette dd
solution est l'approche très manuelle des choses. Si vous en avez besoin régulièrement, il serait facile d'écrire un petit programme qui comble ces lacunes. S'il existe déjà en tant qu'outil standard, je n'en ai pas encore entendu parler.
Il y a un outil après tout, fallocate
semble fonctionner, à la mode:
fallocate -l $(stat --format="%s" sparsefile) sparsefile
Cependant, enfin, dans le cas de XFS, bien qu'il alloue de l'espace physique pour ce fichier, il ne le met pas à zéro. filefrag
affiche les étendues allouées, mais non écrites.
2: 3.. 15: 7628851.. 7628863: 13: 7629020: unwritten
Ce n'est pas suffisant si l'intention est de pouvoir lire les données correctes directement à partir du périphérique de bloc. Il ne réserve que l'espace de stockage nécessaire pour les futures écritures.
cat sparsefile 1<> sparsefile
. Vous pourrez peut-être utiliserfallocate
sous Linux pour éviter d'avoir à écrire ces octets NUL si tout ce que vous voulez, c'est l'espace à allouer.