Trên mặt của nó, nó đơn giản dd
:
dd if=sparsefile of=sparsefile conv=notrunc bs=1M
Nó đọc toàn bộ tập tin và ghi lại toàn bộ nội dung vào nó.
Để chỉ tự viết lỗ, trước tiên bạn phải xác định các lỗ đó ở đâu. Bạn có thể làm điều đó bằng cách sử dụng một trong hai filefrag
hoặc 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
Tệp ví dụ này, như bạn nói, có 10G
kích thước với một 2G
lỗ. Nó có hai phạm vi, bao 0-1048575
thứ nhất 1572864-2621439
, thứ hai , có nghĩa là lỗ đó 1048576-1572864
(trong các khối có kích thước 4k, như được hiển thị bởi filefrag
). Thông tin được hiển thị hdparm
là giống nhau, chỉ hiển thị khác nhau (phạm vi đầu tiên bao gồm các cung từ 8388608
512 byte bắt đầu từ 0 nên 0-4294967295
byte của nó , do đó lỗ được tính 4294967296-6442450944
bằng byte.
Lưu ý rằng dù sao bạn cũng có thể được hiển thị nhiều mức độ hơn nếu có bất kỳ phân mảnh nào. Thật không may, không có lệnh nào hiển thị các lỗ trực tiếp và tôi không biết một lỗ nào như vậy, vì vậy bạn phải suy ra nó từ các giá trị logic được hiển thị.
Bây giờ, lấp đầy 1048576-1572864
lỗ hổng đó dd
như được hiển thị ở trên, có thể được thực hiện bằng cách thêm các giá trị seek
/ giống hệt (và giống hệt) skip
và count
. Lưu ý rằng bs=
đã được điều chỉnh để sử dụng các 4k
lĩnh vực như được sử dụng filefrag
ở trên. (Đối với bs=1M
, bạn phải điều chỉnh các giá trị tìm kiếm / bỏ qua / đếm để phản ánh 1M
các khối có kích thước).
dd if=sparsefile of=sparsefile conv=notrunc \
bs=4k seek=1048576 skip=1048576 count=$((-1048576+1572864))
Mặc dù bạn có thể lấp đầy các lỗ /dev/zero
thay vì đọc lỗ của chính tệp đó (cũng sẽ chỉ mang lại số 0), nhưng an toàn hơn là đọc từ sparsefile
dù sao đi nữa vì vậy bạn sẽ không làm hỏng dữ liệu của mình trong trường hợp bạn bị sai lệch.
Trong các phiên bản mới hơn GNU dd
, bạn có thể dính vào một khối lớn hơn và chỉ định tất cả các giá trị theo byte:
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
sau khi chạy nó:
# 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
Do sự phân mảnh, nó vẫn còn hai phạm vi. Tuy nhiên, phần bù logic cho thấy lần này, không có lỗ hổng, vì vậy tệp không còn thưa thớt nữa.
Đương nhiên, dd
giải pháp này là cách tiếp cận rất thủ công cho mọi thứ. Nếu bạn cần điều này một cách thường xuyên, sẽ dễ dàng viết một chương trình nhỏ lấp đầy những khoảng trống như vậy. Nếu nó đã tồn tại như một công cụ tiêu chuẩn, tôi chưa nghe nói về nó.
Rốt cuộc, có một công cụ, fallocate
dường như hoạt động, sau một thời trang:
fallocate -l $(stat --format="%s" sparsefile) sparsefile
Tuy nhiên, cuối cùng trong trường hợp XFS, trong khi nó phân bổ vùng vật lý cho tệp này, thì nó không thực sự bằng không. filefrag
cho thấy mức độ như được phân bổ, nhưng không được ghi nhận.
2: 3.. 15: 7628851.. 7628863: 13: 7629020: unwritten
Điều này là không đủ nếu mục đích là có thể đọc dữ liệu chính xác trực tiếp từ thiết bị khối. Nó chỉ dự trữ không gian lưu trữ cần thiết cho việc viết trong tương lai.
cat sparsefile 1<> sparsefile
. Bạn có thể sử dụngfallocate
trên Linux để tránh phải ghi các byte NUL đó nếu tất cả những gì bạn muốn là không gian được phân bổ.