zip_unpack_and_sparse.py

Этот скрипт позволяет распаковать zip-файл в случае, когда на диске хватит места для распакованных файлов, но не хватит для распакованных файлов и архива одновременно. Он распаковывает файл и затем стирает его из архива с помощью fallocate — таким образом файлы распаковываются занимаемое место (почти) не увеличивается, однако при этом архив уничтожается (иногда безвозвратно).

Хотя скрипт обмазан многочисленными проверками — он тестировался всего на двух архивах, так что никаких гарантий, на свой страх и риск, вот это вот всё.

Текущие ограничения: сжатие только Deflate, не поддерживаются зашифрованные архивы, права доступа игнорируются, пустые каталоги в архиве игнорируются. Можно допилить по пожеланиям.

Работа скрипта разделена на несколько этапов.

analyze

zip_unpack_and_sparse.py analyze [--check-crc] archive.zip info.json

Команда analyze считывает архив и записывает информацию об оффсетах файла и его заголовок в JSON-файлик.

Сжатие не применяется (но можно допилить, если хочется), так что при большом числе файлов такой JSON-файлик может весить десятки и сотни мегабайт.

Такой предварительный этап позволяет не зависеть от состояния zip-архива и восстановить его в случае если захочется вернуть всё взад.

Можно использовать опцию --check-crc для проверки, что скрипт способен корректно считать файлы из архива, но это, разумеется, займёт дольше времени.

extract

zip_unpack_and_sparse.py extract [--decompress] [--grouped-sparse MiB] [--nosparse] info.json output_directory

Команда, которая собственно вытаскивает файлы из архива в указанный каталог. Он должен быть пустым или не существовать — скрипт его автоматически создать.

Путь к zip-архиву уже указан в JSON-файлике, поэтому указывать его не надо.

Если файлы расжимаются (--decompress), то заодно проверяется CRC32-хэш, и об ошибках сообщается в консольку.

Опции такие:

Если вы вытащили сжатые файлы (без опции --decompress), их можно расжать вручную примерно такой командой:

(echo -en '\x78\xda' && cat myphoto.jpg.zlib) | zlib-flate -uncompress >myphoto.jpg

Команда echo в данном случае добавляет zlib-заголовок. Я не обнаружил влияния разных заголовков на результат, но вот вам на всякий случай ссылочка на RFC 1950, который описывает формат этого заголовка.

restore

Если вы не использовали опцию --decompress и у вас остались вытащенные сжатые файлы и JSON-файлик, вы можете восстановить zip-архив, записав файлы обратно в него.

zip_unpack_and_sparse.py restore info.json output_directory

Из указанного каталога будут читаться файлы и записываться в zip-архив, который прописан в JSON-файлике.

Применение опции --grouped-sparse при распаковке стирает всё пространство между файлами, и если там кроме заголовков оказалось что-то ещё нужное (например, информация о пустых каталогах, которые игноируются скриптом), то zip-архив может не восстановиться, если вы использовали эту опцию. Тестирование на одном из архивов сделало восстановленный zip-архив читабельным, но md5-хэш не сошёлся с оригиналом из-за этих самых пустых папок.