omnizip 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +32 -0
- data/.rubocop_todo.yml +754 -0
- data/COPYING +502 -0
- data/Gemfile +17 -0
- data/LICENSE +12 -0
- data/README.adoc +1045 -0
- data/Rakefile +12 -0
- data/benchmark/README.md +260 -0
- data/benchmark/benchmark_suite.rb +125 -0
- data/benchmark/compression_bench.rb +181 -0
- data/benchmark/filter_bench.rb +180 -0
- data/benchmark/models/benchmark_result.rb +59 -0
- data/benchmark/models/comparison_result.rb +69 -0
- data/benchmark/profile_suite.rb +167 -0
- data/benchmark/reporter.rb +150 -0
- data/benchmark/run_benchmarks.rb +66 -0
- data/benchmark/test_data.rb +137 -0
- data/config/formats/rar3_spec.yml +91 -0
- data/config/formats/rar5_spec.yml +102 -0
- data/docs/.github/workflows/docs.yml +142 -0
- data/docs/.gitignore +21 -0
- data/docs/.lychee.toml +67 -0
- data/docs/Gemfile +13 -0
- data/docs/RAR_WRITE_SUPPORT.md +26 -0
- data/docs/README.md +101 -0
- data/docs/_config.yml +112 -0
- data/docs/assets/logo.svg +1 -0
- data/docs/assets/omnizip-logo.pdf +1540 -11
- data/docs/comparison/feature-matrix.adoc +694 -0
- data/docs/comparison/index.adoc +113 -0
- data/docs/comparison/vs-7zip.adoc +309 -0
- data/docs/comparison/vs-peazip.adoc +77 -0
- data/docs/comparison/vs-rubyzip.adoc +342 -0
- data/docs/comparison/vs-winrar.adoc +100 -0
- data/docs/compatibility.adoc +579 -0
- data/docs/concepts/index.adoc +129 -0
- data/docs/developer/architecture.adoc +256 -0
- data/docs/developer/contributing.adoc +158 -0
- data/docs/developer/index.adoc +25 -0
- data/docs/developer/testing.adoc +212 -0
- data/docs/getting-started/basic-usage.adoc +271 -0
- data/docs/getting-started/index.adoc +42 -0
- data/docs/getting-started/installation.adoc +138 -0
- data/docs/getting-started/quick-start.adoc +185 -0
- data/docs/getting-started/your-first-archive.adoc +218 -0
- data/docs/guides/advanced-features/encryption.adoc +300 -0
- data/docs/guides/advanced-features/index.adoc +49 -0
- data/docs/guides/advanced-features/parallel-processing.adoc +246 -0
- data/docs/guides/advanced-features/progress-tracking.adoc +320 -0
- data/docs/guides/advanced-features/streaming.adoc +212 -0
- data/docs/guides/archive-formats/gzip-format.adoc +107 -0
- data/docs/guides/archive-formats/index.adoc +130 -0
- data/docs/guides/archive-formats/rar-format.adoc +104 -0
- data/docs/guides/archive-formats/rar5.adoc +521 -0
- data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
- data/docs/guides/archive-formats/tar-format.adoc +106 -0
- data/docs/guides/archive-formats/xz-format.adoc +118 -0
- data/docs/guides/archive-formats/zip-format.adoc +35 -0
- data/docs/guides/compression-algorithms/bzip2.adoc +113 -0
- data/docs/guides/compression-algorithms/deflate.adoc +319 -0
- data/docs/guides/compression-algorithms/index.adoc +190 -0
- data/docs/guides/compression-algorithms/lzma.adoc +398 -0
- data/docs/guides/compression-algorithms/lzma2.adoc +327 -0
- data/docs/guides/compression-algorithms/ppmd.adoc +316 -0
- data/docs/guides/compression-algorithms/zstandard.adoc +361 -0
- data/docs/guides/creating-archives.adoc +354 -0
- data/docs/guides/extracting-archives.adoc +53 -0
- data/docs/guides/format-conversion.adoc +64 -0
- data/docs/guides/index.adoc +49 -0
- data/docs/guides/migration-rubyzip.adoc +217 -0
- data/docs/guides/parity-archives.adoc +605 -0
- data/docs/guides/performance-tuning.adoc +88 -0
- data/docs/index.adoc +218 -0
- data/docs/lychee.toml +67 -0
- data/docs/reference/api/overview.adoc +188 -0
- data/docs/reference/cli/compress-command.adoc +114 -0
- data/docs/reference/cli/overview.adoc +140 -0
- data/docs/reference/index.adoc +26 -0
- data/docs/resources/faq.adoc +185 -0
- data/docs/resources/quick-reference.adoc +222 -0
- data/docs/troubleshooting/index.adoc +208 -0
- data/examples/api_comparison.rb +205 -0
- data/examples/deflate64_example.rb +96 -0
- data/examples/par2_demo.rb +121 -0
- data/examples/quick_start_native.rb +150 -0
- data/examples/quick_start_rubyzip.rb +115 -0
- data/examples/rubyzip_compatibility_demo.rb +194 -0
- data/exe/omnizip +27 -0
- data/lib/omnizip/algorithm.rb +130 -0
- data/lib/omnizip/algorithm_registry.rb +86 -0
- data/lib/omnizip/algorithms/.keep +0 -0
- data/lib/omnizip/algorithms/bzip2/bwt.rb +225 -0
- data/lib/omnizip/algorithms/bzip2/decoder.rb +193 -0
- data/lib/omnizip/algorithms/bzip2/encoder.rb +237 -0
- data/lib/omnizip/algorithms/bzip2/huffman.rb +206 -0
- data/lib/omnizip/algorithms/bzip2/mtf.rb +101 -0
- data/lib/omnizip/algorithms/bzip2/rle.rb +151 -0
- data/lib/omnizip/algorithms/bzip2.rb +130 -0
- data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
- data/lib/omnizip/algorithms/deflate/decoder.rb +38 -0
- data/lib/omnizip/algorithms/deflate/encoder.rb +46 -0
- data/lib/omnizip/algorithms/deflate.rb +128 -0
- data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
- data/lib/omnizip/algorithms/deflate64/decoder.rb +153 -0
- data/lib/omnizip/algorithms/deflate64/encoder.rb +98 -0
- data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +354 -0
- data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +142 -0
- data/lib/omnizip/algorithms/deflate64.rb +109 -0
- data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
- data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
- data/lib/omnizip/algorithms/lzma/decoder.rb +148 -0
- data/lib/omnizip/algorithms/lzma/dictionary.rb +69 -0
- data/lib/omnizip/algorithms/lzma/distance_coder.rb +415 -0
- data/lib/omnizip/algorithms/lzma/encoder.rb +142 -0
- data/lib/omnizip/algorithms/lzma/length_coder.rb +260 -0
- data/lib/omnizip/algorithms/lzma/literal_decoder.rb +320 -0
- data/lib/omnizip/algorithms/lzma/literal_encoder.rb +210 -0
- data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +341 -0
- data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +192 -0
- data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
- data/lib/omnizip/algorithms/lzma/match.rb +32 -0
- data/lib/omnizip/algorithms/lzma/match_finder.rb +205 -0
- data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
- data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +88 -0
- data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +130 -0
- data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
- data/lib/omnizip/algorithms/lzma/range_coder.rb +85 -0
- data/lib/omnizip/algorithms/lzma/range_decoder.rb +434 -0
- data/lib/omnizip/algorithms/lzma/range_encoder.rb +194 -0
- data/lib/omnizip/algorithms/lzma/state.rb +127 -0
- data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +325 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder.rb +426 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +645 -0
- data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +227 -0
- data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +169 -0
- data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +261 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +331 -0
- data/lib/omnizip/algorithms/lzma/xz_state.rb +116 -0
- data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +2055 -0
- data/lib/omnizip/algorithms/lzma.rb +238 -0
- data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +182 -0
- data/lib/omnizip/algorithms/lzma2/constants.rb +41 -0
- data/lib/omnizip/algorithms/lzma2/encoder.rb +147 -0
- data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +161 -0
- data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
- data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +127 -0
- data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
- data/lib/omnizip/algorithms/lzma2.rb +141 -0
- data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
- data/lib/omnizip/algorithms/ppmd7/context.rb +154 -0
- data/lib/omnizip/algorithms/ppmd7/decoder.rb +126 -0
- data/lib/omnizip/algorithms/ppmd7/encoder.rb +163 -0
- data/lib/omnizip/algorithms/ppmd7/model.rb +248 -0
- data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
- data/lib/omnizip/algorithms/ppmd7.rb +116 -0
- data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
- data/lib/omnizip/algorithms/ppmd8/context.rb +34 -0
- data/lib/omnizip/algorithms/ppmd8/decoder.rb +107 -0
- data/lib/omnizip/algorithms/ppmd8/encoder.rb +138 -0
- data/lib/omnizip/algorithms/ppmd8/model.rb +250 -0
- data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
- data/lib/omnizip/algorithms/ppmd8.rb +82 -0
- data/lib/omnizip/algorithms/ppmd_base.rb +138 -0
- data/lib/omnizip/algorithms/sevenzip_lzma2.rb +123 -0
- data/lib/omnizip/algorithms/xz_lzma2.rb +118 -0
- data/lib/omnizip/algorithms/zstandard/constants.rb +25 -0
- data/lib/omnizip/algorithms/zstandard/decoder.rb +46 -0
- data/lib/omnizip/algorithms/zstandard/encoder.rb +51 -0
- data/lib/omnizip/algorithms/zstandard.rb +138 -0
- data/lib/omnizip/buffer/memory_archive.rb +251 -0
- data/lib/omnizip/buffer/memory_extractor.rb +224 -0
- data/lib/omnizip/buffer.rb +176 -0
- data/lib/omnizip/checksum_registry.rb +114 -0
- data/lib/omnizip/checksums/crc32.rb +100 -0
- data/lib/omnizip/checksums/crc64.rb +101 -0
- data/lib/omnizip/checksums/crc_base.rb +158 -0
- data/lib/omnizip/checksums/verifier.rb +131 -0
- data/lib/omnizip/chunked/memory_manager.rb +194 -0
- data/lib/omnizip/chunked/reader.rb +78 -0
- data/lib/omnizip/chunked/writer.rb +120 -0
- data/lib/omnizip/chunked.rb +129 -0
- data/lib/omnizip/cli/output_formatter.rb +104 -0
- data/lib/omnizip/cli.rb +572 -0
- data/lib/omnizip/commands/.keep +0 -0
- data/lib/omnizip/commands/archive_create_command.rb +427 -0
- data/lib/omnizip/commands/archive_extract_command.rb +272 -0
- data/lib/omnizip/commands/archive_list_command.rb +218 -0
- data/lib/omnizip/commands/archive_repair_command.rb +131 -0
- data/lib/omnizip/commands/archive_verify_command.rb +117 -0
- data/lib/omnizip/commands/compress_command.rb +117 -0
- data/lib/omnizip/commands/decompress_command.rb +120 -0
- data/lib/omnizip/commands/list_command.rb +53 -0
- data/lib/omnizip/commands/metadata_command.rb +153 -0
- data/lib/omnizip/commands/parity_create_command.rb +122 -0
- data/lib/omnizip/commands/parity_repair_command.rb +122 -0
- data/lib/omnizip/commands/parity_verify_command.rb +124 -0
- data/lib/omnizip/commands/profile_list_command.rb +56 -0
- data/lib/omnizip/commands/profile_show_command.rb +44 -0
- data/lib/omnizip/convenience.rb +359 -0
- data/lib/omnizip/converter/conversion_registry.rb +49 -0
- data/lib/omnizip/converter/conversion_strategy.rb +121 -0
- data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +97 -0
- data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +112 -0
- data/lib/omnizip/converter.rb +105 -0
- data/lib/omnizip/crypto/aes256/cipher.rb +100 -0
- data/lib/omnizip/crypto/aes256/constants.rb +28 -0
- data/lib/omnizip/crypto/aes256/key_derivation.rb +101 -0
- data/lib/omnizip/crypto/aes256.rb +102 -0
- data/lib/omnizip/error.rb +106 -0
- data/lib/omnizip/eta/exponential_smoothing_estimator.rb +98 -0
- data/lib/omnizip/eta/moving_average_estimator.rb +99 -0
- data/lib/omnizip/eta/rate_calculator.rb +104 -0
- data/lib/omnizip/eta/sample_history.rb +143 -0
- data/lib/omnizip/eta/time_estimator.rb +106 -0
- data/lib/omnizip/eta.rb +63 -0
- data/lib/omnizip/extraction/filter_chain.rb +177 -0
- data/lib/omnizip/extraction/glob_pattern.rb +140 -0
- data/lib/omnizip/extraction/pattern_matcher.rb +70 -0
- data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
- data/lib/omnizip/extraction/regex_pattern.rb +50 -0
- data/lib/omnizip/extraction/selective_extractor.rb +240 -0
- data/lib/omnizip/extraction.rb +111 -0
- data/lib/omnizip/file_type/mime_classifier.rb +144 -0
- data/lib/omnizip/file_type.rb +113 -0
- data/lib/omnizip/filter.rb +139 -0
- data/lib/omnizip/filter_pipeline.rb +108 -0
- data/lib/omnizip/filter_registry.rb +166 -0
- data/lib/omnizip/filters/bcj.rb +279 -0
- data/lib/omnizip/filters/bcj2/constants.rb +53 -0
- data/lib/omnizip/filters/bcj2/decoder.rb +200 -0
- data/lib/omnizip/filters/bcj2/encoder.rb +61 -0
- data/lib/omnizip/filters/bcj2/stream_data.rb +93 -0
- data/lib/omnizip/filters/bcj2.rb +99 -0
- data/lib/omnizip/filters/bcj_arm.rb +176 -0
- data/lib/omnizip/filters/bcj_arm64.rb +244 -0
- data/lib/omnizip/filters/bcj_ia64.rb +196 -0
- data/lib/omnizip/filters/bcj_ppc.rb +190 -0
- data/lib/omnizip/filters/bcj_sparc.rb +176 -0
- data/lib/omnizip/filters/bcj_x86.rb +193 -0
- data/lib/omnizip/filters/delta.rb +196 -0
- data/lib/omnizip/filters/filter_base.rb +72 -0
- data/lib/omnizip/filters/registry.rb +123 -0
- data/lib/omnizip/filters/xz_delta.rb +258 -0
- data/lib/omnizip/format_detector.rb +162 -0
- data/lib/omnizip/format_registry.rb +59 -0
- data/lib/omnizip/formats/.keep +0 -0
- data/lib/omnizip/formats/bzip2_file.rb +172 -0
- data/lib/omnizip/formats/cpio/constants.rb +55 -0
- data/lib/omnizip/formats/cpio/entry.rb +385 -0
- data/lib/omnizip/formats/cpio/reader.rb +196 -0
- data/lib/omnizip/formats/cpio/writer.rb +234 -0
- data/lib/omnizip/formats/cpio.rb +140 -0
- data/lib/omnizip/formats/format_spec_loader.rb +230 -0
- data/lib/omnizip/formats/gzip.rb +238 -0
- data/lib/omnizip/formats/iso/directory_builder.rb +297 -0
- data/lib/omnizip/formats/iso/directory_record.rb +152 -0
- data/lib/omnizip/formats/iso/joliet.rb +204 -0
- data/lib/omnizip/formats/iso/path_table.rb +125 -0
- data/lib/omnizip/formats/iso/reader.rb +197 -0
- data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
- data/lib/omnizip/formats/iso/volume_builder.rb +320 -0
- data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
- data/lib/omnizip/formats/iso/writer.rb +530 -0
- data/lib/omnizip/formats/iso.rb +140 -0
- data/lib/omnizip/formats/lzip.rb +175 -0
- data/lib/omnizip/formats/lzma_alone.rb +171 -0
- data/lib/omnizip/formats/rar/archive_repairer.rb +243 -0
- data/lib/omnizip/formats/rar/archive_verifier.rb +195 -0
- data/lib/omnizip/formats/rar/block_parser.rb +243 -0
- data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
- data/lib/omnizip/formats/rar/compression/dispatcher.rb +217 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +216 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +158 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
- data/lib/omnizip/formats/rar/compression/ppmd/context.rb +105 -0
- data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +219 -0
- data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +262 -0
- data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
- data/lib/omnizip/formats/rar/constants.rb +82 -0
- data/lib/omnizip/formats/rar/decompressor.rb +238 -0
- data/lib/omnizip/formats/rar/external_writer.rb +312 -0
- data/lib/omnizip/formats/rar/header.rb +192 -0
- data/lib/omnizip/formats/rar/license_validator.rb +109 -0
- data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
- data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
- data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
- data/lib/omnizip/formats/rar/parity_handler.rb +292 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +202 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +578 -0
- data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
- data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
- data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +97 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +166 -0
- data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
- data/lib/omnizip/formats/rar/rar5/header.rb +187 -0
- data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +264 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +194 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +109 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +142 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
- data/lib/omnizip/formats/rar/rar5/vint.rb +65 -0
- data/lib/omnizip/formats/rar/rar5/writer.rb +466 -0
- data/lib/omnizip/formats/rar/rar_format_base.rb +241 -0
- data/lib/omnizip/formats/rar/reader.rb +366 -0
- data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
- data/lib/omnizip/formats/rar/volume_manager.rb +168 -0
- data/lib/omnizip/formats/rar/writer.rb +431 -0
- data/lib/omnizip/formats/rar.rb +205 -0
- data/lib/omnizip/formats/rar3/compressor.rb +73 -0
- data/lib/omnizip/formats/rar3/decompressor.rb +66 -0
- data/lib/omnizip/formats/rar3/reader.rb +386 -0
- data/lib/omnizip/formats/rar3/writer.rb +219 -0
- data/lib/omnizip/formats/rar5/compressor.rb +73 -0
- data/lib/omnizip/formats/rar5/decompressor.rb +66 -0
- data/lib/omnizip/formats/rar5/reader.rb +342 -0
- data/lib/omnizip/formats/rar5/writer.rb +214 -0
- data/lib/omnizip/formats/seven_zip/coder_chain.rb +150 -0
- data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
- data/lib/omnizip/formats/seven_zip/encoded_header.rb +114 -0
- data/lib/omnizip/formats/seven_zip/encrypted_header.rb +142 -0
- data/lib/omnizip/formats/seven_zip/file_collector.rb +144 -0
- data/lib/omnizip/formats/seven_zip/header.rb +106 -0
- data/lib/omnizip/formats/seven_zip/header_encryptor.rb +134 -0
- data/lib/omnizip/formats/seven_zip/header_writer.rb +466 -0
- data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
- data/lib/omnizip/formats/seven_zip/models/file_entry.rb +58 -0
- data/lib/omnizip/formats/seven_zip/models/folder.rb +69 -0
- data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
- data/lib/omnizip/formats/seven_zip/parser.rb +660 -0
- data/lib/omnizip/formats/seven_zip/reader.rb +458 -0
- data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +632 -0
- data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +315 -0
- data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
- data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +162 -0
- data/lib/omnizip/formats/seven_zip/writer.rb +740 -0
- data/lib/omnizip/formats/seven_zip.rb +93 -0
- data/lib/omnizip/formats/tar/constants.rb +73 -0
- data/lib/omnizip/formats/tar/entry.rb +94 -0
- data/lib/omnizip/formats/tar/header.rb +168 -0
- data/lib/omnizip/formats/tar/reader.rb +121 -0
- data/lib/omnizip/formats/tar/writer.rb +216 -0
- data/lib/omnizip/formats/tar.rb +84 -0
- data/lib/omnizip/formats/xz/reader.rb +116 -0
- data/lib/omnizip/formats/xz.rb +237 -0
- data/lib/omnizip/formats/xz_impl/block_decoder.rb +754 -0
- data/lib/omnizip/formats/xz_impl/block_encoder.rb +306 -0
- data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
- data/lib/omnizip/formats/xz_impl/block_header_parser.rb +186 -0
- data/lib/omnizip/formats/xz_impl/constants.rb +49 -0
- data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
- data/lib/omnizip/formats/xz_impl/index_encoder.rb +122 -0
- data/lib/omnizip/formats/xz_impl/stream_decoder.rb +468 -0
- data/lib/omnizip/formats/xz_impl/stream_encoder.rb +99 -0
- data/lib/omnizip/formats/xz_impl/stream_footer.rb +81 -0
- data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +117 -0
- data/lib/omnizip/formats/xz_impl/stream_header.rb +55 -0
- data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +108 -0
- data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
- data/lib/omnizip/formats/xz_impl/writer.rb +421 -0
- data/lib/omnizip/formats/zip/central_directory_header.rb +195 -0
- data/lib/omnizip/formats/zip/constants.rb +69 -0
- data/lib/omnizip/formats/zip/end_of_central_directory.rb +133 -0
- data/lib/omnizip/formats/zip/local_file_header.rb +138 -0
- data/lib/omnizip/formats/zip/reader.rb +250 -0
- data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
- data/lib/omnizip/formats/zip/writer.rb +375 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +104 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +66 -0
- data/lib/omnizip/formats/zip/zip64_extra_field.rb +114 -0
- data/lib/omnizip/formats/zip.rb +50 -0
- data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
- data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
- data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
- data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
- data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
- data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +421 -0
- data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +465 -0
- data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +288 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +200 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +197 -0
- data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +141 -0
- data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +519 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +723 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +750 -0
- data/lib/omnizip/io/buffered_input.rb +146 -0
- data/lib/omnizip/io/buffered_output.rb +105 -0
- data/lib/omnizip/io/stream_manager.rb +115 -0
- data/lib/omnizip/link_handler/hard_link.rb +79 -0
- data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
- data/lib/omnizip/link_handler.rb +124 -0
- data/lib/omnizip/metadata/archive_metadata.rb +114 -0
- data/lib/omnizip/metadata/entry_metadata.rb +146 -0
- data/lib/omnizip/metadata/metadata_editor.rb +171 -0
- data/lib/omnizip/metadata/metadata_registry.rb +64 -0
- data/lib/omnizip/metadata/metadata_validator.rb +99 -0
- data/lib/omnizip/metadata.rb +57 -0
- data/lib/omnizip/models/.keep +0 -0
- data/lib/omnizip/models/algorithm_metadata.rb +73 -0
- data/lib/omnizip/models/compression_options.rb +71 -0
- data/lib/omnizip/models/conversion_options.rb +87 -0
- data/lib/omnizip/models/conversion_result.rb +135 -0
- data/lib/omnizip/models/eta_result.rb +46 -0
- data/lib/omnizip/models/extraction_rule.rb +115 -0
- data/lib/omnizip/models/filter_chain.rb +144 -0
- data/lib/omnizip/models/filter_config.rb +183 -0
- data/lib/omnizip/models/match_result.rb +124 -0
- data/lib/omnizip/models/optimization_suggestion.rb +91 -0
- data/lib/omnizip/models/parallel_options.rb +104 -0
- data/lib/omnizip/models/performance_result.rb +79 -0
- data/lib/omnizip/models/profile_report.rb +82 -0
- data/lib/omnizip/models/progress_options.rb +38 -0
- data/lib/omnizip/models/split_options.rb +116 -0
- data/lib/omnizip/optimization_registry.rb +81 -0
- data/lib/omnizip/parallel/job_queue.rb +209 -0
- data/lib/omnizip/parallel/job_scheduler.rb +203 -0
- data/lib/omnizip/parallel/parallel_compressor.rb +347 -0
- data/lib/omnizip/parallel/parallel_extractor.rb +329 -0
- data/lib/omnizip/parallel/worker_pool.rb +223 -0
- data/lib/omnizip/parallel.rb +149 -0
- data/lib/omnizip/parity/chunked_block_processor.rb +196 -0
- data/lib/omnizip/parity/galois16.rb +145 -0
- data/lib/omnizip/parity/models/creator_packet.rb +73 -0
- data/lib/omnizip/parity/models/file_description_packet.rb +133 -0
- data/lib/omnizip/parity/models/ifsc_packet.rb +123 -0
- data/lib/omnizip/parity/models/main_packet.rb +128 -0
- data/lib/omnizip/parity/models/packet.rb +156 -0
- data/lib/omnizip/parity/models/packet_registry.rb +109 -0
- data/lib/omnizip/parity/models/recovery_slice_packet.rb +78 -0
- data/lib/omnizip/parity/par2_creator.rb +531 -0
- data/lib/omnizip/parity/par2_repairer.rb +407 -0
- data/lib/omnizip/parity/par2_verifier.rb +364 -0
- data/lib/omnizip/parity/par2cmdline_algorithm.rb +110 -0
- data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
- data/lib/omnizip/parity/reed_solomon_decoder.rb +266 -0
- data/lib/omnizip/parity/reed_solomon_encoder.rb +111 -0
- data/lib/omnizip/parity/reed_solomon_matrix.rb +342 -0
- data/lib/omnizip/parity.rb +186 -0
- data/lib/omnizip/password/encryption_registry.rb +65 -0
- data/lib/omnizip/password/encryption_strategy.rb +96 -0
- data/lib/omnizip/password/password_validator.rb +129 -0
- data/lib/omnizip/password/winzip_aes_strategy.rb +192 -0
- data/lib/omnizip/password/zip_crypto_strategy.rb +141 -0
- data/lib/omnizip/password.rb +87 -0
- data/lib/omnizip/pipe/stream_compressor.rb +124 -0
- data/lib/omnizip/pipe/stream_decompressor.rb +174 -0
- data/lib/omnizip/pipe.rb +121 -0
- data/lib/omnizip/platform/ntfs_streams.rb +201 -0
- data/lib/omnizip/platform.rb +189 -0
- data/lib/omnizip/profile/archive_profile.rb +39 -0
- data/lib/omnizip/profile/balanced_profile.rb +33 -0
- data/lib/omnizip/profile/binary_profile.rb +36 -0
- data/lib/omnizip/profile/compression_profile.rb +158 -0
- data/lib/omnizip/profile/custom_profile.rb +157 -0
- data/lib/omnizip/profile/fast_profile.rb +33 -0
- data/lib/omnizip/profile/maximum_profile.rb +33 -0
- data/lib/omnizip/profile/profile_detector.rb +110 -0
- data/lib/omnizip/profile/profile_registry.rb +161 -0
- data/lib/omnizip/profile/text_profile.rb +36 -0
- data/lib/omnizip/profile.rb +190 -0
- data/lib/omnizip/profiler/memory_profiler.rb +66 -0
- data/lib/omnizip/profiler/method_profiler.rb +49 -0
- data/lib/omnizip/profiler/report_generator.rb +169 -0
- data/lib/omnizip/profiler.rb +204 -0
- data/lib/omnizip/progress/callback_reporter.rb +36 -0
- data/lib/omnizip/progress/console_reporter.rb +62 -0
- data/lib/omnizip/progress/log_reporter.rb +91 -0
- data/lib/omnizip/progress/operation_progress.rb +118 -0
- data/lib/omnizip/progress/progress_bar.rb +156 -0
- data/lib/omnizip/progress/progress_reporter.rb +40 -0
- data/lib/omnizip/progress/progress_tracker.rb +190 -0
- data/lib/omnizip/progress/silent_reporter.rb +24 -0
- data/lib/omnizip/progress.rb +127 -0
- data/lib/omnizip/rubyzip_compat.rb +63 -0
- data/lib/omnizip/temp/safe_extract.rb +168 -0
- data/lib/omnizip/temp/temp_file.rb +124 -0
- data/lib/omnizip/temp/temp_file_pool.rb +109 -0
- data/lib/omnizip/temp.rb +181 -0
- data/lib/omnizip/version.rb +5 -0
- data/lib/omnizip/zip/entry.rb +156 -0
- data/lib/omnizip/zip/file.rb +485 -0
- data/lib/omnizip/zip/input_stream.rb +273 -0
- data/lib/omnizip/zip/output_stream.rb +324 -0
- data/lib/omnizip.rb +156 -0
- data/readme-docs/advanced-features.adoc +515 -0
- data/readme-docs/api-usage.adoc +444 -0
- data/readme-docs/architecture.adoc +449 -0
- data/readme-docs/archive-formats.adoc +479 -0
- data/readme-docs/cli-usage.adoc +222 -0
- data/readme-docs/compression-algorithms.adoc +442 -0
- data/readme-docs/compression-profiles.adoc +247 -0
- data/readme-docs/encryption-checksums.adoc +328 -0
- data/readme-docs/format-converter.adoc +325 -0
- data/readme-docs/installation.adoc +228 -0
- data/readme-docs/par2-archives.adoc +608 -0
- data/readme-docs/performance-profiler.adoc +389 -0
- data/readme-docs/preprocessing-filters.adoc +280 -0
- data/xz-file-format-1.2.1.txt +1174 -0
- metadata +617 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require_relative "constants"
|
|
5
|
+
require_relative "entry"
|
|
6
|
+
|
|
7
|
+
module Omnizip
|
|
8
|
+
module Formats
|
|
9
|
+
module Cpio
|
|
10
|
+
# CPIO archive reader
|
|
11
|
+
#
|
|
12
|
+
# Reads CPIO archives in newc, CRC, ODC, and binary formats.
|
|
13
|
+
# Automatically detects format from magic number.
|
|
14
|
+
#
|
|
15
|
+
# @example Read CPIO archive
|
|
16
|
+
# reader = Cpio::Reader.new('archive.cpio')
|
|
17
|
+
# reader.open
|
|
18
|
+
# reader.entries.each { |entry| puts entry.name }
|
|
19
|
+
#
|
|
20
|
+
# @example Extract CPIO archive
|
|
21
|
+
# reader = Cpio::Reader.new('archive.cpio')
|
|
22
|
+
# reader.open
|
|
23
|
+
# reader.extract_all('output/')
|
|
24
|
+
class Reader
|
|
25
|
+
include Constants
|
|
26
|
+
|
|
27
|
+
# @return [String] Archive file path
|
|
28
|
+
attr_reader :file_path
|
|
29
|
+
|
|
30
|
+
# @return [Array<Entry>] Parsed entries
|
|
31
|
+
attr_reader :entries
|
|
32
|
+
|
|
33
|
+
# @return [Symbol, nil] Detected format
|
|
34
|
+
attr_reader :format
|
|
35
|
+
|
|
36
|
+
# Initialize CPIO reader
|
|
37
|
+
#
|
|
38
|
+
# @param file_path [String] Path to CPIO archive
|
|
39
|
+
def initialize(file_path)
|
|
40
|
+
@file_path = file_path
|
|
41
|
+
@entries = []
|
|
42
|
+
@format = nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Open and parse CPIO archive
|
|
46
|
+
#
|
|
47
|
+
# @raise [RuntimeError] if file cannot be opened or parsed
|
|
48
|
+
def open
|
|
49
|
+
File.open(@file_path, "rb") do |io|
|
|
50
|
+
parse_archive(io)
|
|
51
|
+
end
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# List all entries
|
|
56
|
+
#
|
|
57
|
+
# @return [Array<Entry>] All entries except trailer
|
|
58
|
+
def list
|
|
59
|
+
@entries.reject(&:trailer?)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Extract entry to output path
|
|
63
|
+
#
|
|
64
|
+
# @param entry_name [String] Entry name to extract
|
|
65
|
+
# @param output_path [String] Destination path
|
|
66
|
+
# @raise [RuntimeError] if entry not found
|
|
67
|
+
def extract_entry(entry_name, output_path)
|
|
68
|
+
entry = @entries.find { |e| e.name == entry_name }
|
|
69
|
+
raise "Entry not found: #{entry_name}" unless entry
|
|
70
|
+
|
|
71
|
+
extract_single_entry(entry, output_path)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Extract all entries to directory
|
|
75
|
+
#
|
|
76
|
+
# @param output_dir [String] Output directory
|
|
77
|
+
def extract_all(output_dir)
|
|
78
|
+
FileUtils.mkdir_p(output_dir)
|
|
79
|
+
|
|
80
|
+
@entries.each do |entry|
|
|
81
|
+
next if entry.trailer?
|
|
82
|
+
|
|
83
|
+
output_path = File.join(output_dir, entry.name)
|
|
84
|
+
extract_single_entry(entry, output_path)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Get archive format
|
|
89
|
+
#
|
|
90
|
+
# @return [String] Human-readable format name
|
|
91
|
+
def format_name
|
|
92
|
+
case @format
|
|
93
|
+
when :newc then "CPIO newc (SVR4)"
|
|
94
|
+
when :crc then "CPIO newc with CRC"
|
|
95
|
+
when :odc then "CPIO ODC (portable)"
|
|
96
|
+
when :binary then "CPIO binary (old)"
|
|
97
|
+
else "Unknown"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
# Parse archive contents
|
|
104
|
+
#
|
|
105
|
+
# @param io [IO] Input stream
|
|
106
|
+
def parse_archive(io)
|
|
107
|
+
while !io.eof?
|
|
108
|
+
begin
|
|
109
|
+
entry = Entry.parse(io, format: @format)
|
|
110
|
+
|
|
111
|
+
# Detect format from first entry
|
|
112
|
+
@format ||= Entry.detect_format(entry.magic)
|
|
113
|
+
|
|
114
|
+
# Add entry (including trailer)
|
|
115
|
+
@entries << entry
|
|
116
|
+
|
|
117
|
+
# Stop at trailer
|
|
118
|
+
break if entry.trailer?
|
|
119
|
+
rescue StandardError => e
|
|
120
|
+
warn "Failed to parse CPIO entry: #{e.message}"
|
|
121
|
+
break
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Extract single entry
|
|
127
|
+
#
|
|
128
|
+
# @param entry [Entry] Entry to extract
|
|
129
|
+
# @param output_path [String] Destination path
|
|
130
|
+
def extract_single_entry(entry, output_path)
|
|
131
|
+
if entry.directory?
|
|
132
|
+
extract_directory(entry, output_path)
|
|
133
|
+
elsif entry.symlink?
|
|
134
|
+
extract_symlink(entry, output_path)
|
|
135
|
+
elsif entry.device?
|
|
136
|
+
# Skip device files (require root privileges)
|
|
137
|
+
warn "Skipping device file: #{entry.name}"
|
|
138
|
+
else
|
|
139
|
+
extract_file(entry, output_path)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Set permissions and timestamps
|
|
143
|
+
set_entry_attributes(entry, output_path) unless entry.symlink?
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Extract directory
|
|
147
|
+
#
|
|
148
|
+
# @param entry [Entry] Directory entry
|
|
149
|
+
# @param output_path [String] Destination path
|
|
150
|
+
def extract_directory(_entry, output_path)
|
|
151
|
+
FileUtils.mkdir_p(output_path)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Extract regular file
|
|
155
|
+
#
|
|
156
|
+
# @param entry [Entry] File entry
|
|
157
|
+
# @param output_path [String] Destination path
|
|
158
|
+
def extract_file(entry, output_path)
|
|
159
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
|
160
|
+
File.binwrite(output_path, entry.data)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Extract symbolic link
|
|
164
|
+
#
|
|
165
|
+
# @param entry [Entry] Symlink entry
|
|
166
|
+
# @param output_path [String] Destination path
|
|
167
|
+
def extract_symlink(entry, output_path)
|
|
168
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
|
169
|
+
|
|
170
|
+
# Remove existing file/link if present
|
|
171
|
+
File.unlink(output_path) if File.exist?(output_path) || File.symlink?(output_path)
|
|
172
|
+
|
|
173
|
+
# Create symbolic link
|
|
174
|
+
File.symlink(entry.data, output_path)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Set file attributes (permissions and timestamps)
|
|
178
|
+
#
|
|
179
|
+
# @param entry [Entry] Entry with attributes
|
|
180
|
+
# @param path [String] File path
|
|
181
|
+
def set_entry_attributes(entry, path)
|
|
182
|
+
# Set modification time
|
|
183
|
+
if entry.mtime&.positive?
|
|
184
|
+
mtime = Time.at(entry.mtime)
|
|
185
|
+
File.utime(mtime, mtime, path)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Set permissions
|
|
189
|
+
File.chmod(entry.mode & 0o7777, path) if entry.mode
|
|
190
|
+
rescue Errno::EPERM, Errno::ENOENT
|
|
191
|
+
# Permission errors are non-fatal
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require_relative "constants"
|
|
5
|
+
require_relative "entry"
|
|
6
|
+
|
|
7
|
+
module Omnizip
|
|
8
|
+
module Formats
|
|
9
|
+
module Cpio
|
|
10
|
+
# CPIO archive writer
|
|
11
|
+
#
|
|
12
|
+
# Creates CPIO archives in newc, CRC, or ODC format.
|
|
13
|
+
# Ported from libarchive's archive_write_set_format_cpio_newc.c
|
|
14
|
+
#
|
|
15
|
+
# @example Create CPIO archive
|
|
16
|
+
# writer = Cpio::Writer.new('archive.cpio')
|
|
17
|
+
# writer.add_file('file.txt')
|
|
18
|
+
# writer.add_directory('dir/')
|
|
19
|
+
# writer.write
|
|
20
|
+
#
|
|
21
|
+
# @example With CRC format
|
|
22
|
+
# writer = Cpio::Writer.new('archive.cpio', format: :crc)
|
|
23
|
+
# writer.add_directory('initramfs/')
|
|
24
|
+
# writer.write
|
|
25
|
+
class Writer
|
|
26
|
+
include Constants
|
|
27
|
+
|
|
28
|
+
# @return [String] Output archive path
|
|
29
|
+
attr_reader :output_path
|
|
30
|
+
|
|
31
|
+
# @return [Symbol] CPIO format (:newc, :crc, :odc)
|
|
32
|
+
attr_reader :format
|
|
33
|
+
|
|
34
|
+
# @return [Array<Entry>] Entries to write
|
|
35
|
+
attr_reader :entries
|
|
36
|
+
|
|
37
|
+
# Initialize CPIO writer
|
|
38
|
+
#
|
|
39
|
+
# @param output_path [String] Output CPIO file path
|
|
40
|
+
# @param format [Symbol] CPIO format (:newc, :crc, :odc)
|
|
41
|
+
def initialize(output_path, format: :newc)
|
|
42
|
+
@output_path = output_path
|
|
43
|
+
@format = validate_format(format)
|
|
44
|
+
@entries = []
|
|
45
|
+
@inode_counter = 1
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Add file to archive
|
|
49
|
+
#
|
|
50
|
+
# @param file_path [String] Source file path
|
|
51
|
+
# @param cpio_path [String, nil] Path in archive (defaults to file_path)
|
|
52
|
+
# @raise [ArgumentError] if file doesn't exist
|
|
53
|
+
def add_file(file_path, cpio_path = nil)
|
|
54
|
+
raise ArgumentError, "File not found: #{file_path}" unless
|
|
55
|
+
File.exist?(file_path) || File.symlink?(file_path)
|
|
56
|
+
|
|
57
|
+
# Default to basename if no cpio_path specified
|
|
58
|
+
cpio_path = File.basename(file_path) if cpio_path.nil?
|
|
59
|
+
# Use lstat to not follow symlinks
|
|
60
|
+
stat = File.lstat(file_path)
|
|
61
|
+
|
|
62
|
+
# Normalize path: remove leading slashes to make relative
|
|
63
|
+
cpio_path = cpio_path.sub(%r{^/+}, "")
|
|
64
|
+
|
|
65
|
+
# Read file data unless it's a symlink
|
|
66
|
+
data = if File.symlink?(file_path)
|
|
67
|
+
File.readlink(file_path)
|
|
68
|
+
elsif stat.file?
|
|
69
|
+
File.binread(file_path)
|
|
70
|
+
else
|
|
71
|
+
""
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
entry = create_entry_from_stat(cpio_path, stat, data)
|
|
75
|
+
@entries << entry
|
|
76
|
+
@inode_counter += 1
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Add directory to archive
|
|
80
|
+
#
|
|
81
|
+
# @param dir_path [String] Source directory path
|
|
82
|
+
# @param recursive [Boolean] Include subdirectories
|
|
83
|
+
# @param cpio_path [String, nil] Path in archive
|
|
84
|
+
# @raise [ArgumentError] if directory doesn't exist
|
|
85
|
+
def add_directory(dir_path, recursive: true, cpio_path: nil)
|
|
86
|
+
raise ArgumentError, "Directory not found: #{dir_path}" unless
|
|
87
|
+
Dir.exist?(dir_path)
|
|
88
|
+
|
|
89
|
+
# Default to basename if no cpio_path specified
|
|
90
|
+
cpio_path = File.basename(dir_path) if cpio_path.nil?
|
|
91
|
+
# Normalize path: remove leading slashes to make relative
|
|
92
|
+
cpio_path = cpio_path.sub(%r{^/+}, "")
|
|
93
|
+
stat = File.lstat(dir_path)
|
|
94
|
+
|
|
95
|
+
# Add directory entry
|
|
96
|
+
entry = create_entry_from_stat(cpio_path, stat, "")
|
|
97
|
+
@entries << entry
|
|
98
|
+
@inode_counter += 1
|
|
99
|
+
|
|
100
|
+
# Add contents if recursive
|
|
101
|
+
if recursive
|
|
102
|
+
Dir.foreach(dir_path) do |item|
|
|
103
|
+
next if [".", ".."].include?(item)
|
|
104
|
+
|
|
105
|
+
item_path = File.join(dir_path, item)
|
|
106
|
+
item_cpio_path = "#{cpio_path}/#{item}"
|
|
107
|
+
|
|
108
|
+
if File.directory?(item_path)
|
|
109
|
+
add_directory(item_path, recursive: true,
|
|
110
|
+
cpio_path: item_cpio_path)
|
|
111
|
+
else
|
|
112
|
+
add_file(item_path, item_cpio_path)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Write CPIO archive
|
|
119
|
+
#
|
|
120
|
+
# @raise [IOError] if write fails
|
|
121
|
+
def write
|
|
122
|
+
File.open(@output_path, "wb") do |io|
|
|
123
|
+
# Write all entries
|
|
124
|
+
@entries.each do |entry|
|
|
125
|
+
write_entry(io, entry)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Write trailer
|
|
129
|
+
write_trailer(io)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
@output_path
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
private
|
|
136
|
+
|
|
137
|
+
# Validate format
|
|
138
|
+
#
|
|
139
|
+
# @param format [Symbol] Format to validate
|
|
140
|
+
# @return [Symbol] Validated format
|
|
141
|
+
# @raise [ArgumentError] if format invalid
|
|
142
|
+
def validate_format(format)
|
|
143
|
+
unless %i[newc crc odc].include?(format)
|
|
144
|
+
raise ArgumentError, "Invalid CPIO format: #{format}. " \
|
|
145
|
+
"Must be :newc, :crc, or :odc"
|
|
146
|
+
end
|
|
147
|
+
format
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Create entry from file stat
|
|
151
|
+
#
|
|
152
|
+
# @param path [String] Entry path
|
|
153
|
+
# @param stat [File::Stat] File statistics
|
|
154
|
+
# @param data [String] File data
|
|
155
|
+
# @return [Entry] Created entry
|
|
156
|
+
def create_entry_from_stat(path, stat, data)
|
|
157
|
+
Entry.new(
|
|
158
|
+
magic: format_magic,
|
|
159
|
+
ino: @inode_counter,
|
|
160
|
+
mode: stat.mode,
|
|
161
|
+
uid: stat.uid,
|
|
162
|
+
gid: stat.gid,
|
|
163
|
+
nlink: stat.nlink,
|
|
164
|
+
mtime: stat.mtime.to_i,
|
|
165
|
+
filesize: data.bytesize,
|
|
166
|
+
dev_major: (stat.dev >> 8) & 0xFF,
|
|
167
|
+
dev_minor: stat.dev & 0xFF,
|
|
168
|
+
rdev_major: stat.rdev ? (stat.rdev >> 8) & 0xFF : 0,
|
|
169
|
+
rdev_minor: stat.rdev ? (stat.rdev & 0xFF) : 0,
|
|
170
|
+
namesize: path.bytesize + 1,
|
|
171
|
+
checksum: @format == :crc ? calculate_checksum(data) : 0,
|
|
172
|
+
name: path,
|
|
173
|
+
data: data,
|
|
174
|
+
)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Get magic number for current format
|
|
178
|
+
#
|
|
179
|
+
# @return [String] Magic number
|
|
180
|
+
def format_magic
|
|
181
|
+
case @format
|
|
182
|
+
when :newc then MAGIC_NEWC
|
|
183
|
+
when :crc then MAGIC_CRC
|
|
184
|
+
when :odc then MAGIC_ODC
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Write entry to archive
|
|
189
|
+
#
|
|
190
|
+
# @param io [IO] Output stream
|
|
191
|
+
# @param entry [Entry] Entry to write
|
|
192
|
+
def write_entry(io, entry)
|
|
193
|
+
binary_data = entry.to_binary(format: @format)
|
|
194
|
+
io.write(binary_data)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Write trailer entry
|
|
198
|
+
#
|
|
199
|
+
# @param io [IO] Output stream
|
|
200
|
+
def write_trailer(io)
|
|
201
|
+
trailer = Entry.new(
|
|
202
|
+
magic: format_magic,
|
|
203
|
+
ino: 0,
|
|
204
|
+
mode: 0,
|
|
205
|
+
uid: 0,
|
|
206
|
+
gid: 0,
|
|
207
|
+
nlink: 1,
|
|
208
|
+
mtime: 0,
|
|
209
|
+
filesize: 0,
|
|
210
|
+
dev_major: 0,
|
|
211
|
+
dev_minor: 0,
|
|
212
|
+
rdev_major: 0,
|
|
213
|
+
rdev_minor: 0,
|
|
214
|
+
namesize: TRAILER_NAME.bytesize + 1,
|
|
215
|
+
checksum: 0,
|
|
216
|
+
name: TRAILER_NAME,
|
|
217
|
+
data: "",
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
write_entry(io, trailer)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Calculate checksum for CRC format
|
|
224
|
+
#
|
|
225
|
+
# @param data [String] Data to checksum
|
|
226
|
+
# @return [Integer] CRC32 checksum
|
|
227
|
+
def calculate_checksum(data)
|
|
228
|
+
require "zlib"
|
|
229
|
+
Zlib.crc32(data) & 0xFFFFFFFF
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "cpio/constants"
|
|
4
|
+
require_relative "cpio/entry"
|
|
5
|
+
require_relative "cpio/writer"
|
|
6
|
+
require_relative "cpio/reader"
|
|
7
|
+
|
|
8
|
+
module Omnizip
|
|
9
|
+
module Formats
|
|
10
|
+
# CPIO archive format support
|
|
11
|
+
#
|
|
12
|
+
# Provides read and write access to CPIO archives in multiple formats:
|
|
13
|
+
# - newc (SVR4 new ASCII format) - Most common, used in initramfs
|
|
14
|
+
# - CRC (newc with CRC checksums)
|
|
15
|
+
# - ODC (Old portable ASCII format)
|
|
16
|
+
#
|
|
17
|
+
# CPIO is commonly used for:
|
|
18
|
+
# - Linux initramfs/initrd
|
|
19
|
+
# - RPM package contents
|
|
20
|
+
# - Unix system backups
|
|
21
|
+
#
|
|
22
|
+
# @example Create CPIO archive
|
|
23
|
+
# Omnizip::Formats::Cpio.create('archive.cpio') do |cpio|
|
|
24
|
+
# cpio.add_directory('files/')
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# @example Extract CPIO archive
|
|
28
|
+
# Omnizip::Formats::Cpio.extract('archive.cpio', 'output/')
|
|
29
|
+
module Cpio
|
|
30
|
+
class << self
|
|
31
|
+
# Create CPIO archive
|
|
32
|
+
#
|
|
33
|
+
# @param path [String] Output CPIO file path
|
|
34
|
+
# @param format [Symbol] CPIO format (:newc, :crc, :odc)
|
|
35
|
+
# @yield [writer] Block for adding files/directories
|
|
36
|
+
# @yieldparam writer [Writer] CPIO writer
|
|
37
|
+
# @return [String] Path to created archive
|
|
38
|
+
#
|
|
39
|
+
# @example Create newc format archive
|
|
40
|
+
# Omnizip::Formats::Cpio.create('archive.cpio') do |cpio|
|
|
41
|
+
# cpio.add_file('kernel.img')
|
|
42
|
+
# cpio.add_directory('modules/')
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# @example Create with CRC checksums
|
|
46
|
+
# Omnizip::Formats::Cpio.create('archive.cpio', format: :crc) do |cpio|
|
|
47
|
+
# cpio.add_directory('initramfs/')
|
|
48
|
+
# end
|
|
49
|
+
def create(path, format: :newc)
|
|
50
|
+
writer = Writer.new(path, format: format)
|
|
51
|
+
|
|
52
|
+
yield writer if block_given?
|
|
53
|
+
|
|
54
|
+
writer.write
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Open CPIO archive for reading
|
|
58
|
+
#
|
|
59
|
+
# @param path [String] Path to CPIO file
|
|
60
|
+
# @yield [reader] Block for reading archive
|
|
61
|
+
# @yieldparam reader [Reader] CPIO reader
|
|
62
|
+
# @return [Reader] CPIO reader
|
|
63
|
+
#
|
|
64
|
+
# @example Read CPIO archive
|
|
65
|
+
# Omnizip::Formats::Cpio.open('archive.cpio') do |cpio|
|
|
66
|
+
# cpio.entries.each { |entry| puts entry.name }
|
|
67
|
+
# end
|
|
68
|
+
def open(path)
|
|
69
|
+
reader = Reader.new(path)
|
|
70
|
+
reader.open
|
|
71
|
+
|
|
72
|
+
if block_given?
|
|
73
|
+
yield reader
|
|
74
|
+
else
|
|
75
|
+
reader
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# List CPIO archive contents
|
|
80
|
+
#
|
|
81
|
+
# @param path [String] Path to CPIO file
|
|
82
|
+
# @return [Array<Entry>] Archive entries
|
|
83
|
+
#
|
|
84
|
+
# @example List archive contents
|
|
85
|
+
# entries = Omnizip::Formats::Cpio.list('archive.cpio')
|
|
86
|
+
# entries.each { |e| puts "#{e.name} (#{e.filesize} bytes)" }
|
|
87
|
+
def list(path)
|
|
88
|
+
open(path, &:list)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Extract CPIO archive
|
|
92
|
+
#
|
|
93
|
+
# @param cpio_path [String] Path to CPIO file
|
|
94
|
+
# @param output_dir [String] Output directory
|
|
95
|
+
#
|
|
96
|
+
# @example Extract archive
|
|
97
|
+
# Omnizip::Formats::Cpio.extract('archive.cpio', 'output/')
|
|
98
|
+
def extract(cpio_path, output_dir)
|
|
99
|
+
open(cpio_path) do |cpio|
|
|
100
|
+
cpio.extract_all(output_dir)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Get archive information
|
|
105
|
+
#
|
|
106
|
+
# @param path [String] Path to CPIO file
|
|
107
|
+
# @return [Hash] Archive information
|
|
108
|
+
#
|
|
109
|
+
# @example Get archive info
|
|
110
|
+
# info = Omnizip::Formats::Cpio.info('archive.cpio')
|
|
111
|
+
# puts "Format: #{info[:format]}"
|
|
112
|
+
# puts "Files: #{info[:file_count]}"
|
|
113
|
+
def info(path)
|
|
114
|
+
open(path) do |cpio|
|
|
115
|
+
entries = cpio.list
|
|
116
|
+
|
|
117
|
+
{
|
|
118
|
+
format: cpio.format_name,
|
|
119
|
+
format_type: cpio.format,
|
|
120
|
+
entry_count: entries.size,
|
|
121
|
+
file_count: entries.count(&:file?),
|
|
122
|
+
directory_count: entries.count(&:directory?),
|
|
123
|
+
symlink_count: entries.count(&:symlink?),
|
|
124
|
+
total_size: entries.sum(&:filesize),
|
|
125
|
+
}
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Auto-register CPIO format when loaded
|
|
130
|
+
def register!
|
|
131
|
+
require_relative "../format_registry"
|
|
132
|
+
FormatRegistry.register(".cpio", Reader)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Auto-register on load
|
|
140
|
+
Omnizip::Formats::Cpio.register!
|