Tạo lưu trữ tar (hoặc khác), với dữ liệu được căn chỉnh khối như trong các tệp gốc để sao chép cấp khối tốt hơn?


8

Làm cách nào để tạo một tệp tar, vì vậy nội dung của các tệp tarred được căn chỉnh khối như trong các tệp gốc, do đó, người ta có thể hưởng lợi từ việc sao chép cấp khối ( https://unix.stackexchange.com/a/208847/9689 ) ?

.

PS Tôi có nghĩa là "tar không nén" - không phải tar + gz hoặc một cái gì đó - tar không nén và câu hỏi yêu cầu một số mẹo cho phép căn chỉnh mức khối tệp. AFAIRecall tar được thiết kế để sử dụng với máy băng, vì vậy có thể thêm một số bit bổ sung để căn chỉnh là có thể và dễ dàng trong định dạng tệp? Tôi hy vọng có thể có công cụ thậm chí cho nó;). Theo như tôi nhớ các tập tin tar có thể được nối, vì vậy có thể sẽ có mẹo để lấp đầy không gian để căn chỉnh.


Người ta thường kết hợp tar với một số loại nén, mà ngay cả khi điều này chỉ hoạt động với tar, chắc chắn sẽ không với nén.
psusi

Ồ Câu hỏi hay và thông minh.
Adam Ryczkowski

Câu trả lời:


3

Nó có thể được thực hiện, trên lý thuyết. Nhưng nó rất xấu và chủ yếu liên quan đến việc xây dựng kho lưu trữ của chúng tôi bằng tay.

Chúng ta đang chống lại cái gì

Các tarđịnh dạng hoạt động trên các khối 512 byte . Kích thước này là cố định và được dự định để phù hợp với kích thước khu vực đĩa truyền thống. Khi lưu trữ tệp trong kho lưu trữ, khối 512 byte đầu tiên là tiêu đề chứa siêu dữ liệu tệp (tên, kích thước, loại, v.v.) và các khối sau chứa nội dung tệp. Vì vậy, dữ liệu lưu trữ của chúng tôi sẽ bị sai lệch bởi 512 byte.

Kích thước khối ("--sectorize") của btrfs thường là 4096 byte . Về lý thuyết chúng ta có thể chọn cái này, nhưng trong thực tế có vẻ như nó phải phù hợp với kích thước trang của CPU của chúng ta. Vì vậy, chúng tôi không thể thu nhỏ các khối btrfs.

Các tarchương trình có một khái niệm về kích thước "kỷ lục" lớn hơn, định nghĩa là một bội số của kích thước khối, mà hầu như trông giống như nó sẽ là hữu ích. Nó chỉ ra rằng điều này có nghĩa là để xác định kích thước khu vực của một ổ đĩa băng nhất định, do đó tarsẽ tránh ghi các bản ghi băng một phần. Tuy nhiên, dữ liệu vẫn được xây dựng và đóng gói theo đơn vị 512 byte, vì vậy chúng tôi không thể sử dụng dữ liệu này để phát triển tarcác khối như bạn mong muốn.

Một điểm cuối cùng của dữ liệu để ai biết được rằng tar's end-of-archive marker là hai all-zero liền khối, trừ khi những khối là dữ liệu tập tin bên trong. Vì vậy, bất kỳ loại khối đệm ngây thơ có lẽ sẽ không được chấp nhận.

Hack

Những gì chúng ta có thể làm là chèn các tập tin đệm. Khi bắt đầu lưu trữ của chúng tôi, trước khi chúng tôi thêm tệp chúng tôi muốn sao chép (gọi nó dup), chúng tôi thêm một tệp pad, có kích thước sao cho

pad's header + pad's data + dup's header = 4096 bytes.

Bằng cách đó, dupdữ liệu của bắt đầu tại một ranh giới khối và có thể được lặp lại.

Sau đó, đối với mỗi tệp tiếp theo, chúng tôi cũng phải theo dõi kích thước của tệp trước đó để tính toán phần đệm chính xác. Chúng tôi cũng phải dự đoán liệu có cần một số phần mở rộng tiêu đề hay không: ví dụ, tiêu đề tar cơ bản chỉ có chỗ cho 100 byte đường dẫn tệp, do đó, các đường dẫn dài hơn được mã hóa bằng cách sử dụng một tệp có tên đặc biệt có dữ liệu con đường đầy đủ. Nhìn chung, có rất nhiều sự phức tạp tiềm năng trong việc dự đoán kích thước tiêu đề - tarđịnh dạng tệp có rất nhiều hành động từ nhiều triển khai lịch sử.

Một lớp lót bạc nhỏ là tất cả các tệp đệm có thể chia sẻ cùng một tên, vì vậy khi chúng ta hủy kết thúc, chúng ta sẽ chỉ kết thúc với một tệp bổ sung có kích thước nhỏ hơn 4096 byte.

Cách rõ ràng nhất để tạo một kho lưu trữ như thế này có lẽ là sửa đổi tarchương trình GNU . Nhưng nếu bạn muốn nhanh chóng và bẩn thỉu với chi phí CPU và thời gian I / O, bạn có thể, đối với mỗi tệp, hãy làm một cái gì đó như:

#!/bin/bash

# Proof of concept and probably buggy.
# If I ever find this script in a production environment,
# I don't know whether I'll laugh or cry.

my_file="$2"
my_archive="$1"

file_size="$(wc -c <"$my_file")"
arch_size="$(tar cb 1 "$my_file" | wc -c)"  # "b 1": Remember that record size I mentioned?  Set it to equal the block size so we can measure usefully.
end_marker_size=1024  # End-of-archive marker: 2 blocks' worth of 0 bytes

hdr_size="$(( (arch_size - file_size - end_marker_size) % 4096 ))"
pad_size="$(( (4096 - 512 - hdr_size) % 4096 ))"
(( pad_size < 512 )) && pad_size="$(( pad_size + 4096 ))"

# Assume the pre-existing archive is already a multiple of 4096 bytes long
# (not including the end-of-archive marker), and add extra padding to the end
# so that it stays that way.
file_blocks_size="$(( ((file_size+511) / 512) * 512 ))"
end_pad_size="$(( 4096 - 512 - (file_blocks_size % 4096) ))"
(( end_pad_size < 512 )) && end_pad_size="$(( end_pad_size + 4096 ))"

head -c $pad_size /dev/zero > _PADDING_
tar rf "$my_archive" _PADDING_ "$my_file"
head -c $end_pad_size /dev/zero > _PADDING_
tar rf "$my_archive" _PADDING_
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.