hrev47473 adds 4 changesets to branch 'master' old head: d229332a33feb23d9ca9f3869ec7c4e4b09a990f new head: a629567a9001547736cfe892cdf992be16868fed overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=a629567+%5Ed229332 ---------------------------------------------------------------------------- f5a20d5: package kit: PackageFileHeapReader::Init(): Sanity checks Make sure the compressed/uncompressed heap size and the chunk size table look plausible, so we can rely on the values later. Fixes potential crashes for corrupt packages. 2fc2aeb: PackageWriterImpl: Move _Finish() impl to match order in header cdfeba5: BPackageWriter: Add Recompress() Allows rewriting an existing package file with a different compression. a629567: package: Add command recompress The streaming feature for -0 is missing yet. [ Ingo Weinhold <ingo_weinhold@xxxxxx> ] ---------------------------------------------------------------------------- 15 files changed, 380 insertions(+), 68 deletions(-) headers/os/package/hpkg/PackageReader.h | 4 + headers/os/package/hpkg/PackageWriter.h | 6 + .../package/hpkg/PackageFileHeapAccessorBase.h | 4 + headers/private/package/hpkg/PackageReaderImpl.h | 5 + headers/private/package/hpkg/PackageWriterImpl.h | 6 + headers/private/package/hpkg/WriterImplBase.h | 8 + src/bin/package/Jamfile | 1 + src/bin/package/command_recompress.cpp | 128 ++++++++++++ src/bin/package/package.cpp | 16 ++ src/bin/package/package.h | 1 + .../package/hpkg/PackageFileHeapAccessorBase.cpp | 10 + src/kits/package/hpkg/PackageFileHeapReader.cpp | 38 +++- src/kits/package/hpkg/PackageWriter.cpp | 12 ++ src/kits/package/hpkg/PackageWriterImpl.cpp | 208 +++++++++++++------ src/tools/package/Jamfile | 1 + ############################################################################ Commit: f5a20d5ff15b0153a8df4733ef28f5b3bc2b8489 URL: http://cgit.haiku-os.org/haiku/commit/?id=f5a20d5 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Jul 7 18:59:05 2014 UTC package kit: PackageFileHeapReader::Init(): Sanity checks Make sure the compressed/uncompressed heap size and the chunk size table look plausible, so we can rely on the values later. Fixes potential crashes for corrupt packages. ---------------------------------------------------------------------------- diff --git a/src/kits/package/hpkg/PackageFileHeapReader.cpp b/src/kits/package/hpkg/PackageFileHeapReader.cpp index 6b19326..056ca4d 100644 --- a/src/kits/package/hpkg/PackageFileHeapReader.cpp +++ b/src/kits/package/hpkg/PackageFileHeapReader.cpp @@ -44,17 +44,32 @@ PackageFileHeapReader::~PackageFileHeapReader() status_t PackageFileHeapReader::Init() { - if (fUncompressedHeapSize == 0) + if (fUncompressedHeapSize == 0) { + if (fCompressedHeapSize != 0) { + fErrorOutput->PrintError( + "Invalid total compressed heap size (!= 0, empty heap)\n"); + return B_BAD_DATA; + } return B_OK; + } // Determine number of chunks and adjust the compressed heap size (subtract // the size of the chunk size array at the end). Note that the size of the - // last chunk has not been saved, since it size is implied. + // last chunk has not been saved, since its size is implied. ssize_t chunkCount = (fUncompressedHeapSize + kChunkSize - 1) / kChunkSize; - if (chunkCount <= 0) + if (chunkCount == 0) return B_OK; - fCompressedHeapSize -= (chunkCount - 1) * 2; + size_t chunkSizeTableSize = (chunkCount - 1) * 2; + if (fCompressedHeapSize <= chunkSizeTableSize) { + fErrorOutput->PrintError( + "Invalid total compressed heap size (%" B_PRIu64 ", " + "uncompressed %" B_PRIu64 ")\n", fCompressedHeapSize, + fUncompressedHeapSize); + return B_BAD_DATA; + } + + fCompressedHeapSize -= chunkSizeTableSize; // allocate a buffer uint16* buffer = (uint16*)malloc(kChunkSize); @@ -80,6 +95,21 @@ PackageFileHeapReader::Init() offset += toRead * 2; } + // Sanity check: The sum of the chunk sizes must match the compressed heap + // size. The information aren't stored redundantly, so we check, if things + // look at least plausible. + uint64 lastChunkOffset = fOffsets[chunkCount - 1]; + if (lastChunkOffset >= fCompressedHeapSize + || fCompressedHeapSize - lastChunkOffset > kChunkSize + || fCompressedHeapSize - lastChunkOffset + > fUncompressedHeapSize - (chunkCount - 1) * kChunkSize) { + fErrorOutput->PrintError( + "Invalid total compressed heap size (%" B_PRIu64 ", uncompressed: " + "%" B_PRIu64 ", last chunk offset: %" B_PRIu64 ")\n", + fCompressedHeapSize, fUncompressedHeapSize, lastChunkOffset); + return B_BAD_DATA; + } + return B_OK; } ############################################################################ Commit: 2fc2aebcba504f169142344ff04ae75fbb0e7ccb URL: http://cgit.haiku-os.org/haiku/commit/?id=2fc2aeb Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Jul 7 19:31:25 2014 UTC PackageWriterImpl: Move _Finish() impl to match order in header ---------------------------------------------------------------------------- diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp index 8f5cadd..ed717dd 100644 --- a/src/kits/package/hpkg/PackageWriterImpl.cpp +++ b/src/kits/package/hpkg/PackageWriterImpl.cpp @@ -662,6 +662,69 @@ PackageWriterImpl::_Init(const char* fileName, status_t +PackageWriterImpl::_Finish() +{ + // write entries + for (EntryList::ConstIterator it = fRootEntry->ChildIterator(); + Entry* entry = it.Next();) { + char pathBuffer[B_PATH_NAME_LENGTH]; + pathBuffer[0] = '\0'; + _AddEntry(AT_FDCWD, entry, entry->Name(), pathBuffer); + } + + hpkg_header header; + + // write the TOC and package attributes + uint64 tocLength; + _WriteTOC(header, tocLength); + + uint64 attributesLength; + _WritePackageAttributes(header, attributesLength); + + // flush the heap + status_t error = fHeapWriter->Finish(); + if (error != B_OK) + return error; + + uint64 compressedHeapSize = fHeapWriter->CompressedHeapSize(); + + header.heap_compression = B_HOST_TO_BENDIAN_INT16(B_HPKG_COMPRESSION_ZLIB); + header.heap_chunk_size = B_HOST_TO_BENDIAN_INT32(fHeapWriter->ChunkSize()); + header.heap_size_compressed = B_HOST_TO_BENDIAN_INT64(compressedHeapSize); + header.heap_size_uncompressed = B_HOST_TO_BENDIAN_INT64( + fHeapWriter->UncompressedHeapSize()); + + // Truncate the file to the size it is supposed to have. In update mode, it + // can be greater when one or more files are shrunk. In creation mode it + // should already have the correct size. + off_t totalSize = fHeapWriter->HeapOffset() + (off_t)compressedHeapSize; + if (ftruncate(FD(), totalSize) != 0) { + fListener->PrintError("Failed to truncate package file to new " + "size: %s\n", strerror(errno)); + return errno; + } + + fListener->OnPackageSizeInfo(fHeaderSize, compressedHeapSize, tocLength, + attributesLength, totalSize); + + // prepare the header + + // general + header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC); + header.header_size = B_HOST_TO_BENDIAN_INT16(fHeaderSize); + header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_VERSION); + header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize); + header.minor_version = B_HOST_TO_BENDIAN_INT16(B_HPKG_MINOR_VERSION); + + // write the header + RawWriteBuffer(&header, sizeof(hpkg_header), 0); + + SetFinished(true); + return B_OK; +} + + +status_t PackageWriterImpl::_CheckLicenses() { BPath systemLicensePath; @@ -1071,70 +1134,6 @@ PackageWriterImpl::_AttributeRemoved(Attribute* attribute) status_t -PackageWriterImpl::_Finish() -{ - // write entries - for (EntryList::ConstIterator it = fRootEntry->ChildIterator(); - Entry* entry = it.Next();) { - char pathBuffer[B_PATH_NAME_LENGTH]; - pathBuffer[0] = '\0'; - _AddEntry(AT_FDCWD, entry, entry->Name(), pathBuffer); - } - - hpkg_header header; - - // write the TOC and package attributes - uint64 tocLength; - _WriteTOC(header, tocLength); - - uint64 attributesLength; - _WritePackageAttributes(header, attributesLength); - - // flush the heap - status_t error = fHeapWriter->Finish(); - if (error != B_OK) - return error; - - uint64 compressedHeapSize = fHeapWriter->CompressedHeapSize(); - - header.heap_compression = B_HOST_TO_BENDIAN_INT16(B_HPKG_COMPRESSION_ZLIB); - header.heap_chunk_size = B_HOST_TO_BENDIAN_INT32(fHeapWriter->ChunkSize()); - header.heap_size_compressed = B_HOST_TO_BENDIAN_INT64( - fHeapWriter->CompressedHeapSize()); - header.heap_size_uncompressed = B_HOST_TO_BENDIAN_INT64( - fHeapWriter->UncompressedHeapSize()); - - // Truncate the file to the size it is supposed to have. In update mode, it - // can be greater when one or more files are shrunk. In creation mode it - // should already have the correct size. - off_t totalSize = fHeapWriter->HeapOffset() + (off_t)compressedHeapSize; - if (ftruncate(FD(), totalSize) != 0) { - fListener->PrintError("Failed to truncate package file to new " - "size: %s\n", strerror(errno)); - return errno; - } - - fListener->OnPackageSizeInfo(fHeaderSize, compressedHeapSize, tocLength, - attributesLength, totalSize); - - // prepare the header - - // general - header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC); - header.header_size = B_HOST_TO_BENDIAN_INT16(fHeaderSize); - header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_VERSION); - header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize); - header.minor_version = B_HOST_TO_BENDIAN_INT16(B_HPKG_MINOR_VERSION); - - // write the header - RawWriteBuffer(&header, sizeof(hpkg_header), 0); - - SetFinished(true); - return B_OK; -} - - -status_t PackageWriterImpl::_RegisterEntry(const char* fileName, int fd) { if (*fileName == '\0') { ############################################################################ Commit: cdfeba5a1e49d0993e7ab6853c77392bbc10d3c4 URL: http://cgit.haiku-os.org/haiku/commit/?id=cdfeba5 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Tue Jul 8 19:58:10 2014 UTC BPackageWriter: Add Recompress() Allows rewriting an existing package file with a different compression. ---------------------------------------------------------------------------- diff --git a/headers/os/package/hpkg/PackageReader.h b/headers/os/package/hpkg/PackageReader.h index e5b8369..7ab4976 100644 --- a/headers/os/package/hpkg/PackageReader.h +++ b/headers/os/package/hpkg/PackageReader.h @@ -24,6 +24,7 @@ class BAbstractBufferedDataReader; class BErrorOutput; class BLowLevelPackageContentHandler; class BPackageContentHandler; +class BPackageWriter; class BPackageReader { @@ -44,6 +45,9 @@ public: // Only valid as long as the reader lives. private: + friend class BPackageWriter; + +private: PackageReaderImpl* fImpl; }; diff --git a/headers/os/package/hpkg/PackageWriter.h b/headers/os/package/hpkg/PackageWriter.h index 99c924b..996f83f 100644 --- a/headers/os/package/hpkg/PackageWriter.h +++ b/headers/os/package/hpkg/PackageWriter.h @@ -16,6 +16,9 @@ namespace BPackageKit { namespace BHPKG { +class BPackageReader; + + namespace BPrivate { class PackageWriterImpl; } @@ -72,6 +75,9 @@ public: status_t AddEntry(const char* fileName, int fd = -1); status_t Finish(); + status_t Recompress(BPackageReader* reader); + // to be called after Init(); no Finish() + private: PackageWriterImpl* fImpl; }; diff --git a/headers/private/package/hpkg/PackageFileHeapAccessorBase.h b/headers/private/package/hpkg/PackageFileHeapAccessorBase.h index 2d9eed3..b5463dd 100644 --- a/headers/private/package/hpkg/PackageFileHeapAccessorBase.h +++ b/headers/private/package/hpkg/PackageFileHeapAccessorBase.h @@ -92,6 +92,10 @@ public: void SetFD(int fd) { fFD = fd; } + uint64 HeapOverhead(uint64 uncompressedSize) const; + // additional bytes needed when storing + // the given amount of data + // BAbstractBufferedDataReader virtual status_t ReadDataToOutput(off_t offset, size_t size, BDataIO* output); diff --git a/headers/private/package/hpkg/PackageReaderImpl.h b/headers/private/package/hpkg/PackageReaderImpl.h index aaac66c..3f7522b 100644 --- a/headers/private/package/hpkg/PackageReaderImpl.h +++ b/headers/private/package/hpkg/PackageReaderImpl.h @@ -22,6 +22,9 @@ class BPackageEntryAttribute; namespace BPrivate { +class PackageWriterImpl; + + class PackageReaderImpl : public ReaderImplBase { typedef ReaderImplBase inherited; public: @@ -58,6 +61,8 @@ private: struct EntryAttributeHandler; struct RootAttributeHandler; + friend class PackageWriterImpl; + private: status_t _ParseTOC(AttributeHandlerContext* context, AttributeHandler* rootAttributeHandler); diff --git a/headers/private/package/hpkg/PackageWriterImpl.h b/headers/private/package/hpkg/PackageWriterImpl.h index f74c1ba..1202783 100644 --- a/headers/private/package/hpkg/PackageWriterImpl.h +++ b/headers/private/package/hpkg/PackageWriterImpl.h @@ -35,6 +35,7 @@ class BPackageWriterParameters; namespace BPrivate { +class PackageReaderImpl; struct hpkg_header; @@ -53,6 +54,9 @@ public: status_t AddEntry(const char* fileName, int fd = -1); status_t Finish(); + status_t Recompress(PackageReaderImpl* reader); + // to be called after Init(); no Finish() + private: struct Attribute; struct PackageContentHandler; @@ -67,6 +71,8 @@ private: const BPackageWriterParameters& parameters); status_t _Finish(); + status_t _Recompress(PackageReaderImpl* reader); + status_t _RegisterEntry(const char* fileName, int fd); Entry* _RegisterEntry(Entry* parent, const char* name, size_t nameLength, int fd, diff --git a/headers/private/package/hpkg/WriterImplBase.h b/headers/private/package/hpkg/WriterImplBase.h index 99afd30..38496c4 100644 --- a/headers/private/package/hpkg/WriterImplBase.h +++ b/headers/private/package/hpkg/WriterImplBase.h @@ -151,6 +151,7 @@ protected: inline int FD() const; inline uint32 Flags() const; + inline const BPackageWriterParameters& Parameters() const; inline const PackageAttributeList& PackageAttributes() const; inline PackageAttributeList& PackageAttributes(); @@ -230,6 +231,13 @@ WriterImplBase::Flags() const } +inline const BPackageWriterParameters& +WriterImplBase::Parameters() const +{ + return fParameters; +} + + inline const WriterImplBase::PackageAttributeList& WriterImplBase::PackageAttributes() const { diff --git a/src/kits/package/hpkg/PackageFileHeapAccessorBase.cpp b/src/kits/package/hpkg/PackageFileHeapAccessorBase.cpp index ebc2d10..b8981e1 100644 --- a/src/kits/package/hpkg/PackageFileHeapAccessorBase.cpp +++ b/src/kits/package/hpkg/PackageFileHeapAccessorBase.cpp @@ -144,6 +144,16 @@ PackageFileHeapAccessorBase::~PackageFileHeapAccessorBase() } +uint64 +PackageFileHeapAccessorBase::HeapOverhead(uint64 uncompressedSize) const +{ + // Determine number of chunks and the size of the chunk size table. Note + // that the size of the last chunk is not saved, since its size is implied. + size_t chunkCount = (uncompressedSize + kChunkSize - 1) / kChunkSize; + return chunkCount > 1 ? (chunkCount - 1) * 2 : 0; +} + + status_t PackageFileHeapAccessorBase::ReadDataToOutput(off_t offset, size_t size, BDataIO* output) diff --git a/src/kits/package/hpkg/PackageWriter.cpp b/src/kits/package/hpkg/PackageWriter.cpp index 2a5582e..15b877f 100644 --- a/src/kits/package/hpkg/PackageWriter.cpp +++ b/src/kits/package/hpkg/PackageWriter.cpp @@ -8,6 +8,8 @@ #include <new> +#include <package/hpkg/PackageReader.h> + #include <package/hpkg/PackageWriterImpl.h> @@ -128,6 +130,16 @@ BPackageWriter::Finish() } +status_t +BPackageWriter::Recompress(BPackageReader* reader) +{ + if (fImpl == NULL) + return B_NO_INIT; + + return fImpl->Recompress(reader->fImpl); +} + + } // namespace BHPKG } // namespace BPackageKit diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp index ed717dd..740f454 100644 --- a/src/kits/package/hpkg/PackageWriterImpl.cpp +++ b/src/kits/package/hpkg/PackageWriterImpl.cpp @@ -38,6 +38,7 @@ #include <package/hpkg/HPKGDefsPrivate.h> #include <package/hpkg/DataReader.h> +#include <package/hpkg/PackageFileHeapReader.h> #include <package/hpkg/PackageFileHeapWriter.h> #include <package/hpkg/PackageReaderImpl.h> #include <package/hpkg/Stacker.h> @@ -606,6 +607,23 @@ PackageWriterImpl::Finish() status_t +PackageWriterImpl::Recompress(PackageReaderImpl* reader) +{ + if (reader == NULL) + return B_BAD_VALUE; + + try { + return _Recompress(reader); + } catch (status_t error) { + return error; + } catch (std::bad_alloc) { + fListener->PrintError("Out of memory!\n"); + return B_NO_MEMORY; + } +} + + +status_t PackageWriterImpl::_Init(const char* fileName, const BPackageWriterParameters& parameters) { @@ -725,6 +743,69 @@ PackageWriterImpl::_Finish() status_t +PackageWriterImpl::_Recompress(PackageReaderImpl* reader) +{ + if (reader == NULL) + return B_BAD_VALUE; + + // read the header + hpkg_header header; + status_t error = reader->ReadBuffer(0, &header, sizeof(header)); + if (error != B_OK) { + fListener->PrintError("Failed to reader hpkg header: %s\n", + strerror(error)); + return error; + } + + // Update some header fields, assuming no compression. We'll rewrite the + // header later, should compression have been used. Doing it this way allows + // for streaming an uncompressed package. + uint64 uncompressedHeapSize + = reader->RawHeapReader()->UncompressedHeapSize(); + uint64 compressedHeapSize = uncompressedHeapSize + + fHeapWriter->HeapOverhead(uncompressedHeapSize); + + off_t totalSize = fHeapWriter->HeapOffset() + (off_t)compressedHeapSize; + + header.heap_compression = B_HOST_TO_BENDIAN_INT16(B_HPKG_COMPRESSION_ZLIB); + header.heap_chunk_size = B_HOST_TO_BENDIAN_INT32(fHeapWriter->ChunkSize()); + header.heap_size_compressed = B_HOST_TO_BENDIAN_INT64(compressedHeapSize); + header.heap_size_uncompressed + = B_HOST_TO_BENDIAN_INT64(uncompressedHeapSize); + header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize); + + if (Parameters().CompressionLevel() == 0) + RawWriteBuffer(&header, sizeof(hpkg_header), 0); + + // copy the heap data + uint64 bytesCompressed; + error = fHeapWriter->AddData(*reader->RawHeapReader(), uncompressedHeapSize, + bytesCompressed); + if (error != B_OK) + return error; + + // flush the heap + error = fHeapWriter->Finish(); + if (error != B_OK) + return error; + + // If compression is enabled, update and write the header. + if (Parameters().CompressionLevel() != 0) { + compressedHeapSize = fHeapWriter->CompressedHeapSize(); + totalSize = fHeapWriter->HeapOffset() + (off_t)compressedHeapSize; + header.heap_size_compressed = B_HOST_TO_BENDIAN_INT64(compressedHeapSize); + header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize); + + // write the header + RawWriteBuffer(&header, sizeof(hpkg_header), 0); + } + + SetFinished(true); + return B_OK; +} + + +status_t PackageWriterImpl::_CheckLicenses() { BPath systemLicensePath; ############################################################################ Revision: hrev47473 Commit: a629567a9001547736cfe892cdf992be16868fed URL: http://cgit.haiku-os.org/haiku/commit/?id=a629567 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Tue Jul 8 19:59:44 2014 UTC package: Add command recompress The streaming feature for -0 is missing yet. ---------------------------------------------------------------------------- diff --git a/src/bin/package/Jamfile b/src/bin/package/Jamfile index 80f0c95..111b2de 100644 --- a/src/bin/package/Jamfile +++ b/src/bin/package/Jamfile @@ -9,6 +9,7 @@ BinCommand package : command_extract.cpp command_info.cpp command_list.cpp + command_recompress.cpp package.cpp PackageWriterListener.cpp PackageWritingUtils.cpp diff --git a/src/bin/package/command_recompress.cpp b/src/bin/package/command_recompress.cpp new file mode 100644 index 0000000..b1cd6d0 --- /dev/null +++ b/src/bin/package/command_recompress.cpp @@ -0,0 +1,128 @@ +/* + * Copyright 2014, Ingo Weinhold, ingo_weinhold@xxxxxx. + * Distributed under the terms of the MIT License. + */ + + +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <package/hpkg/HPKGDefs.h> +#include <package/hpkg/PackageReader.h> +#include <package/hpkg/PackageWriter.h> + +#include "package.h" +#include "PackageWriterListener.h" + + +using BPackageKit::BHPKG::BPackageReader; +using BPackageKit::BHPKG::BPackageWriter; +using BPackageKit::BHPKG::BPackageWriterListener; +using BPackageKit::BHPKG::BPackageWriterParameters; + + +int +command_recompress(int argc, const char* const* argv) +{ + bool quiet = false; + bool verbose = false; + int32 compressionLevel = BPackageKit::BHPKG::B_HPKG_COMPRESSION_LEVEL_BEST; + + while (true) { + static struct option sLongOptions[] = { + { "help", no_argument, 0, 'h' }, + { "quiet", no_argument, 0, 'q' }, + { "verbose", no_argument, 0, 'v' }, + { 0, 0, 0, 0 } + }; + + opterr = 0; // don't print errors + int c = getopt_long(argc, (char**)argv, "+0123456789:hqv", + sLongOptions, NULL); + if (c == -1) + break; + + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + compressionLevel = c - '0'; + break; + + case 'h': + print_usage_and_exit(false); + break; + + case 'q': + quiet = true; + break; + + case 'v': + verbose = true; + break; + + default: + print_usage_and_exit(true); + break; + } + } + + // The remaining arguments are the input package file and optionally the + // output package file, i.e. one or two more arguments. + if (argc - optind < 1 || argc - optind > 2) + print_usage_and_exit(true); + + const char* inputPackageFileName = argv[optind++]; + const char* outputPackageFileName = optind < argc ? argv[optind++] : NULL; + + // If compression is used, an output file is required. + if (compressionLevel != 0 && outputPackageFileName == NULL) { + fprintf(stderr, "Error: Writing to stdout is supported only with " + "compression level 0.\n"); + return 1; + } + + // TODO: Implement streaming support! + if (outputPackageFileName == NULL) { + fprintf(stderr, "Error: Writing to stdout is not supported yet.\n"); + return 1; + } + + // open the input package + PackageWriterListener listener(verbose, quiet); + + BPackageReader packageReader(&listener); + status_t error = packageReader.Init(inputPackageFileName); + if (error != B_OK) + return 1; + + // write the output package + BPackageWriterParameters writerParameters; + writerParameters.SetCompressionLevel(compressionLevel); + + BPackageWriter packageWriter(&listener); + error = packageWriter.Init(outputPackageFileName, &writerParameters); + if (error != B_OK) + return 1; + + error = packageWriter.Recompress(&packageReader); + if (error != B_OK) + return 1; + + if (verbose) + printf("\nsuccessfully wrote package '%s'\n", outputPackageFileName); + + return 0; +} diff --git a/src/bin/package/package.cpp b/src/bin/package/package.cpp index 627755f..6bcab5c 100644 --- a/src/bin/package/package.cpp +++ b/src/bin/package/package.cpp @@ -96,6 +96,19 @@ static const char* kUsage = " -i - Only print the meta information, not the files.\n" " -p - Only print a list of file paths.\n" "\n" + " recompress [ <options> ] <input package> [ <output package> ]\n" + " Reads the package file <input package> and writes it to new package\n" + " <output package> using the specified compression options. If the\n" + " compression level 0 is specified (i.e. no compression), " + "<output package>\n" + " can be omitted, in which case the data are written to stdout.\n" + "\n" + " -0 ... -9 - Use compression level 0 ... 9. 0 means no, 9 best " + "compression.\n" + " Defaults to 9.\n" + " -q - Be quiet (don't show any output except for errors).\n" + " -v - Be verbose (show more info about created package).\n" + "\n" "Common Options:\n" " -h, --help - Print this usage info.\n" ; @@ -134,6 +147,9 @@ main(int argc, const char* const* argv) if (strcmp(command, "info") == 0) return command_info(argc - 1, argv + 1); + if (strcmp(command, "recompress") == 0) + return command_recompress(argc - 1, argv + 1); + if (strcmp(command, "help") == 0) print_usage_and_exit(false); else diff --git a/src/bin/package/package.h b/src/bin/package/package.h index 966386b..f15268b 100644 --- a/src/bin/package/package.h +++ b/src/bin/package/package.h @@ -14,6 +14,7 @@ int command_dump(int argc, const char* const* argv); int command_extract(int argc, const char* const* argv); int command_info(int argc, const char* const* argv); int command_list(int argc, const char* const* argv); +int command_recompress(int argc, const char* const* argv); #endif // PACKAGE_H diff --git a/src/tools/package/Jamfile b/src/tools/package/Jamfile index b9dfd36..891bf6d 100644 --- a/src/tools/package/Jamfile +++ b/src/tools/package/Jamfile @@ -13,6 +13,7 @@ BuildPlatformMain <build>package : command_extract.cpp command_info.cpp command_list.cpp + command_recompress.cpp package.cpp PackageWriterListener.cpp PackageWritingUtils.cpp