hpkg format: compress the whole heap

Instead of handling compression for individual file/attribute data we
do now compress the whole heap where they are stored. This
significantly improves compression ratios. We still divide the
uncompressed data into 64 KiB chunks and use a chunk offset array for
the compressed chunks to allow for quick random access without too much
overhead. The tradeoff is a limited possible compression ratio -- i.e.
we won't be as good as tar.gz (though surprisingly with my test
archives we did better than zip).

The other package file sections (package attributes and TOC) are no
longer compressed individually. Their uncompressed data are simply
pushed onto the heap where the usual compression strategy applies. To
simplify things the repository format has been changed in the same
manner although it doesn't otherwise use the heap, since it only stores
meta data.

Due to the data compression having been exposed in public and private
API, this change touches a lot of package kit using code, including
packagefs and the boot loader packagefs support. The latter two haven't
been tested yet. Moreover packagefs needs a new kind of cache so we
avoid re-reading the same heap chunk for two different data items it
contains.
This commit is contained in:
Ingo Weinhold
2013-05-25 01:12:25 +02:00
parent 16e5e5e4ec
commit 1f633814fa
50 changed files with 2732 additions and 2132 deletions
@@ -0,0 +1 @@
#include <../private/package/hpkg/DataWriters.h>
@@ -0,0 +1 @@
#include <../private/package/hpkg/PackageFileHeapAccessorBase.h>
@@ -0,0 +1 @@
#include <../private/package/hpkg/PackageFileHeapReader.h>
@@ -0,0 +1 @@
#include <../private/package/hpkg/PackageFileHeapWriter.h>
+30 -35
View File
@@ -20,7 +20,7 @@ enum {
B_HPKG_VERSION = 2,
//
B_HPKG_REPO_MAGIC = 'hpkr',
B_HPKG_REPO_VERSION = 1
B_HPKG_REPO_VERSION = 2
};
@@ -98,37 +98,34 @@ enum BHPKGAttributeID {
B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE = 11,
B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE_TYPE = 12,
B_HPKG_ATTRIBUTE_ID_DATA = 13,
B_HPKG_ATTRIBUTE_ID_DATA_SIZE = 14,
B_HPKG_ATTRIBUTE_ID_DATA_COMPRESSION = 15,
B_HPKG_ATTRIBUTE_ID_DATA_CHUNK_SIZE = 16,
B_HPKG_ATTRIBUTE_ID_SYMLINK_PATH = 17,
B_HPKG_ATTRIBUTE_ID_PACKAGE_NAME = 18,
B_HPKG_ATTRIBUTE_ID_PACKAGE_SUMMARY = 19,
B_HPKG_ATTRIBUTE_ID_PACKAGE_DESCRIPTION = 20,
B_HPKG_ATTRIBUTE_ID_PACKAGE_VENDOR = 21,
B_HPKG_ATTRIBUTE_ID_PACKAGE_PACKAGER = 22,
B_HPKG_ATTRIBUTE_ID_PACKAGE_FLAGS = 23,
B_HPKG_ATTRIBUTE_ID_PACKAGE_ARCHITECTURE = 24,
B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR = 25,
B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MINOR = 26,
B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MICRO = 27,
B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_REVISION = 28,
B_HPKG_ATTRIBUTE_ID_PACKAGE_COPYRIGHT = 29,
B_HPKG_ATTRIBUTE_ID_PACKAGE_LICENSE = 30,
B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES = 31,
B_HPKG_ATTRIBUTE_ID_PACKAGE_REQUIRES = 32,
B_HPKG_ATTRIBUTE_ID_PACKAGE_SUPPLEMENTS = 33,
B_HPKG_ATTRIBUTE_ID_PACKAGE_CONFLICTS = 34,
B_HPKG_ATTRIBUTE_ID_PACKAGE_FRESHENS = 35,
B_HPKG_ATTRIBUTE_ID_PACKAGE_REPLACES = 36,
B_HPKG_ATTRIBUTE_ID_PACKAGE_RESOLVABLE_OPERATOR = 37,
B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM = 38,
B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE = 39,
B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_COMPATIBLE = 40,
B_HPKG_ATTRIBUTE_ID_PACKAGE_URL = 41,
B_HPKG_ATTRIBUTE_ID_PACKAGE_SOURCE_URL = 42,
B_HPKG_ATTRIBUTE_ID_PACKAGE_INSTALL_PATH = 43,
B_HPKG_ATTRIBUTE_ID_PACKAGE_BASE_PACKAGE = 44,
B_HPKG_ATTRIBUTE_ID_SYMLINK_PATH = 14,
B_HPKG_ATTRIBUTE_ID_PACKAGE_NAME = 15,
B_HPKG_ATTRIBUTE_ID_PACKAGE_SUMMARY = 16,
B_HPKG_ATTRIBUTE_ID_PACKAGE_DESCRIPTION = 17,
B_HPKG_ATTRIBUTE_ID_PACKAGE_VENDOR = 18,
B_HPKG_ATTRIBUTE_ID_PACKAGE_PACKAGER = 19,
B_HPKG_ATTRIBUTE_ID_PACKAGE_FLAGS = 20,
B_HPKG_ATTRIBUTE_ID_PACKAGE_ARCHITECTURE = 21,
B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR = 22,
B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MINOR = 23,
B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MICRO = 24,
B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_REVISION = 25,
B_HPKG_ATTRIBUTE_ID_PACKAGE_COPYRIGHT = 26,
B_HPKG_ATTRIBUTE_ID_PACKAGE_LICENSE = 27,
B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES = 28,
B_HPKG_ATTRIBUTE_ID_PACKAGE_REQUIRES = 29,
B_HPKG_ATTRIBUTE_ID_PACKAGE_SUPPLEMENTS = 30,
B_HPKG_ATTRIBUTE_ID_PACKAGE_CONFLICTS = 31,
B_HPKG_ATTRIBUTE_ID_PACKAGE_FRESHENS = 32,
B_HPKG_ATTRIBUTE_ID_PACKAGE_REPLACES = 33,
B_HPKG_ATTRIBUTE_ID_PACKAGE_RESOLVABLE_OPERATOR = 34,
B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM = 35,
B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE = 36,
B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_COMPATIBLE = 37,
B_HPKG_ATTRIBUTE_ID_PACKAGE_URL = 38,
B_HPKG_ATTRIBUTE_ID_PACKAGE_SOURCE_URL = 39,
B_HPKG_ATTRIBUTE_ID_PACKAGE_INSTALL_PATH = 40,
B_HPKG_ATTRIBUTE_ID_PACKAGE_BASE_PACKAGE = 41,
//
B_HPKG_ATTRIBUTE_ID_ENUM_COUNT,
};
@@ -154,9 +151,7 @@ enum {
B_HPKG_DEFAULT_FILE_TYPE = B_HPKG_FILE_TYPE_FILE,
B_HPKG_DEFAULT_FILE_PERMISSIONS = 0644,
B_HPKG_DEFAULT_DIRECTORY_PERMISSIONS = 0755,
B_HPKG_DEFAULT_SYMLINK_PERMISSIONS = 0777,
B_HPKG_DEFAULT_DATA_COMPRESSION = B_HPKG_COMPRESSION_NONE,
B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB = 64 * 1024
B_HPKG_DEFAULT_SYMLINK_PERMISSIONS = 0777
};
+4 -18
View File
@@ -18,14 +18,10 @@ class BPackageData {
public:
BPackageData();
uint64 CompressedSize() const
{ return fCompressedSize; }
uint64 UncompressedSize() const
{ return fUncompressedSize; }
uint64 Size() const
{ return fSize; }
uint64 Offset() const
{ return fEncodedInline ? 0 : fOffset; }
uint32 Compression() const { return fCompression; }
uint32 ChunkSize() const { return fChunkSize; }
bool IsEncodedInline() const
{ return fEncodedInline; }
@@ -34,23 +30,13 @@ public:
void SetData(uint64 size, uint64 offset);
void SetData(uint8 size, const void* data);
void SetCompression(uint32 compression)
{ fCompression = compression; }
void SetUncompressedSize(uint64 size)
{ fUncompressedSize = size; }
void SetChunkSize(uint32 size)
{ fChunkSize = size; }
private:
uint64 fCompressedSize;
uint64 fUncompressedSize;
uint64 fSize : 63;
bool fEncodedInline : 1;
union {
uint64 fOffset;
uint8 fInlineData[B_HPKG_MAX_INLINE_DATA_SIZE];
};
uint32 fChunkSize;
uint32 fCompression;
bool fEncodedInline;
};
+3 -6
View File
@@ -20,15 +20,12 @@ class BPackageData;
class BPackageDataReaderFactory {
public:
BPackageDataReaderFactory(
BBufferPool* bufferPool);
BPackageDataReaderFactory();
status_t CreatePackageDataReader(BDataReader* dataReader,
status_t CreatePackageDataReader(
BAbstractBufferedDataReader* dataReader,
const BPackageData& data,
BAbstractBufferedDataReader*& _reader);
private:
BBufferPool* fBufferPool;
};
+7 -2
View File
@@ -19,6 +19,8 @@ namespace BPrivate {
}
using BPrivate::PackageReaderImpl;
class BAbstractBufferedDataReader;
class BErrorOutput;
class BLowLevelPackageContentHandler;
class BPackageContentHandler;
@@ -26,8 +28,7 @@ class BPackageContentHandler;
class BPackageReader {
public:
BPackageReader(
BErrorOutput* errorOutput);
BPackageReader(BErrorOutput* errorOutput);
~BPackageReader();
status_t Init(const char* fileName);
@@ -38,6 +39,10 @@ public:
contentHandler);
int PackageFileFD();
BAbstractBufferedDataReader* HeapReader() const;
// Only valid as long as the reader lives.
private:
PackageReaderImpl* fImpl;
};
@@ -19,6 +19,7 @@ namespace BPrivate {
}
using BPrivate::RepositoryReaderImpl;
class BErrorOutput;
class BRepositoryContentHandler;
+101
View File
@@ -0,0 +1,101 @@
/*
* Copyright 2011, Oliver Tappe <[email protected]>
* Copyright 2013, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _PACKAGE__HPKG__PRIVATE__DATA_WRITERS_H_
#define _PACKAGE__HPKG__PRIVATE__DATA_WRITERS_H_
#include <package/hpkg/DataOutput.h>
#include <package/hpkg/ZlibCompressor.h>
namespace BPackageKit {
namespace BHPKG {
class BErrorOutput;
namespace BPrivate {
class AbstractDataWriter {
public:
AbstractDataWriter();
virtual ~AbstractDataWriter();
uint64 BytesWritten() const
{ return fBytesWritten; }
virtual status_t WriteDataNoThrow(const void* buffer,
size_t size) = 0;
void WriteDataThrows(const void* buffer,
size_t size);
protected:
uint64 fBytesWritten;
};
class FDDataWriter : public AbstractDataWriter {
public:
FDDataWriter(int fd, off_t offset,
BErrorOutput* errorOutput);
virtual status_t WriteDataNoThrow(const void* buffer,
size_t size);
off_t Offset() const
{ return fOffset; }
private:
int fFD;
off_t fOffset;
BErrorOutput* fErrorOutput;
};
class ZlibDataWriter : public AbstractDataWriter, private BDataOutput {
public:
ZlibDataWriter(AbstractDataWriter* dataWriter);
void Init();
void Finish();
virtual status_t WriteDataNoThrow(const void* buffer,
size_t size);
private:
// BDataOutput
virtual status_t WriteData(const void* buffer, size_t size);
private:
AbstractDataWriter* fDataWriter;
ZlibCompressor fCompressor;
};
// inline implementations
inline void
AbstractDataWriter::WriteDataThrows(const void* buffer, size_t size)
{
status_t error = WriteDataNoThrow(buffer, size);
if (error != B_OK)
throw status_t(error);
}
} // namespace BPrivate
} // namespace BHPKG
} // namespace BPackageKit
#endif // _PACKAGE__HPKG__PRIVATE__DATA_WRITERS_H_
+16 -15
View File
@@ -18,7 +18,7 @@ namespace BHPKG {
namespace BPrivate {
// header
// package file header
struct hpkg_header {
uint32 magic; // "hpkg"
uint16 header_size;
@@ -26,40 +26,41 @@ struct hpkg_header {
uint64 total_size;
// heap
// uint64 heap_compression;
uint32 heap_compression;
uint32 heap_chunk_size;
uint64 heap_size_compressed;
uint64 heap_size_uncompressed;
// package attributes section
uint32 attributes_compression;
uint32 attributes_length_compressed;
uint32 attributes_length_uncompressed;
uint32 attributes_length;
uint32 attributes_strings_length;
uint32 attributes_strings_count;
// TOC section
uint32 toc_compression;
uint64 toc_length_compressed;
uint64 toc_length_uncompressed;
uint64 toc_length;
uint64 toc_strings_length;
uint64 toc_strings_count;
};
// header
// repository file header
struct hpkg_repo_header {
uint32 magic; // "hpkr"
uint16 header_size;
uint16 version;
uint64 total_size;
// heap
uint32 heap_compression;
uint32 heap_chunk_size;
uint64 heap_size_compressed;
uint64 heap_size_uncompressed;
// repository info section
uint32 info_compression;
uint32 info_length_compressed;
uint32 info_length_uncompressed;
uint32 info_length;
// package attributes section
uint32 packages_compression;
uint64 packages_length_compressed;
uint64 packages_length_uncompressed;
uint64 packages_length;
uint64 packages_strings_length;
uint64 packages_strings_count;
};
@@ -0,0 +1,143 @@
/*
* Copyright 2013, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_ACCESSOR_BASE_H_
#define _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_ACCESSOR_BASE_H_
#include <SupportDefs.h>
#include <package/hpkg/DataReader.h>
namespace BPackageKit {
namespace BHPKG {
class BErrorOutput;
namespace BPrivate {
class PackageFileHeapAccessorBase : public BAbstractBufferedDataReader {
public:
class OffsetArray;
public:
PackageFileHeapAccessorBase(
BErrorOutput* errorOutput, int fd,
off_t heapOffset);
virtual ~PackageFileHeapAccessorBase();
off_t HeapOffset() const
{ return fHeapOffset; }
off_t CompressedHeapSize() const
{ return fCompressedHeapSize; }
uint64 UncompressedHeapSize() const
{ return fUncompressedHeapSize; }
size_t ChunkSize() const
{ return kChunkSize; }
// normally used after cloning a PackageFileHeapReader only
void SetErrorOutput(BErrorOutput* errorOutput)
{ fErrorOutput = errorOutput; }
void SetFD(int fd)
{ fFD = fd; }
// BAbstractBufferedDataReader
virtual status_t ReadDataToOutput(off_t offset, size_t size,
BDataOutput* output);
public:
static const size_t kChunkSize = 64 * 1024;
protected:
virtual status_t ReadAndDecompressChunk(size_t chunkIndex,
void* compressedDataBuffer,
void* uncompressedDataBuffer) = 0;
status_t ReadAndDecompressChunkData(uint64 offset,
size_t compressedSize,
size_t uncompressedSize,
void* compressedDataBuffer,
void* uncompressedDataBuffer);
status_t ReadFileData(uint64 offset, void* buffer,
size_t size);
protected:
BErrorOutput* fErrorOutput;
int fFD;
off_t fHeapOffset;
uint64 fCompressedHeapSize;
uint64 fUncompressedHeapSize;
};
/*! Stores the chunk offsets in a compact way, while still providing quick
access.
- The object doesn't store the number of chunks/offsets it contains. During
initialization the chunk count is provided. Later, when getting an offset,
the caller is responsible for ensuring a valid index.
- The first (index 0) chunk offset is omitted, since it is always 0.
- The chunk offsets that fit in a 32 bit number use only one 32 bit element
in the offsets array.
- The chunk offsets that don't fit in a 32 bit number use two elements in
the offsets array.
Memory use is one pointer, if the chunk count is <= 1 (uncompressed heap size
<= 64 KiB). Afterwards it's one pointer plus 32 bit per chunk as long as the
last offset still fits 32 bit (compressed heap size < 4GiB). For any further
chunks it is 64 bit per chunk. So, for the common case we use sizeof(void*)
plus 1 KiB per 16 MiB of uncompressed heap, or about 64 KiB per 1 GiB. Which
seems reasonable for packagefs to keep in memory.
*/
class PackageFileHeapAccessorBase::OffsetArray {
public:
OffsetArray();
~OffsetArray();
bool InitChunksOffsets(size_t totalChunkCount,
size_t baseIndex, const uint16* chunkSizes,
size_t chunkCount);
bool Init(size_t totalChunkCount,
const OffsetArray& other);
// "copy" init
uint64 operator[](size_t index) const;
private:
uint32* fOffsets;
// - NULL, if chunkCount <= 1
// - element 0 contains the number of 32 bit
// offsets that follow, or is 0, when all
// offsets are 32 bit only
// - the following offsets use two elements
// each (lower followed by upper 32 bit)
// to represent the 64 bit value
};
inline uint64
PackageFileHeapAccessorBase::OffsetArray::operator[](size_t index) const
{
if (index == 0)
return 0;
if (fOffsets[0] == 0 || index < fOffsets[0])
return fOffsets[index];
index += index - fOffsets[0];
return fOffsets[index] | ((uint64)fOffsets[index + 1] << 32);
}
} // namespace BPrivate
} // namespace BHPKG
} // namespace BPackageKit
#endif // _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_ACCESSOR_BASE_H_
@@ -0,0 +1,57 @@
/*
* Copyright 2013, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_READER_H_
#define _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_READER_H_
#include <Array.h>
#include <package/hpkg/PackageFileHeapAccessorBase.h>
namespace BPackageKit {
namespace BHPKG {
class BDataReader;
class BErrorOutput;
namespace BPrivate {
class PackageFileHeapReader : public PackageFileHeapAccessorBase {
public:
PackageFileHeapReader(BErrorOutput* errorOutput,
int fd, off_t heapOffset,
off_t compressedHeapSize,
uint64 uncompressedHeapSize);
~PackageFileHeapReader();
status_t Init();
PackageFileHeapReader* Clone() const;
const OffsetArray& Offsets() const
{ return fOffsets; }
protected:
virtual status_t ReadAndDecompressChunk(size_t chunkIndex,
void* compressedDataBuffer,
void* uncompressedDataBuffer);
private:
OffsetArray fOffsets;
};
} // namespace BPrivate
} // namespace BHPKG
} // namespace BPackageKit
#endif // _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_READER_H_
@@ -0,0 +1,99 @@
/*
* Copyright 2013, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_WRITER_H_
#define _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_WRITER_H_
#include <Array.h>
#include <package/hpkg/DataWriters.h>
#include <package/hpkg/PackageFileHeapAccessorBase.h>
namespace BPrivate {
template<typename Value> class RangeArray;
}
namespace BPackageKit {
namespace BHPKG {
class BDataReader;
class BErrorOutput;
namespace BPrivate {
class PackageFileHeapReader;
class PackageFileHeapWriter : public PackageFileHeapAccessorBase,
private AbstractDataWriter {
public:
PackageFileHeapWriter(BErrorOutput* errorOutput,
int fd, off_t heapOffset);
~PackageFileHeapWriter();
void Init();
void Reinit(PackageFileHeapReader* heapReader);
AbstractDataWriter* DataWriter()
{ return this; }
status_t AddData(BDataReader& dataReader, off_t size,
uint64& _offset);
void RemoveDataRanges(
const ::BPrivate::RangeArray<uint64>&
ranges);
// doesn't truncate the file
status_t Finish();
protected:
virtual status_t ReadAndDecompressChunk(size_t chunkIndex,
void* compressedDataBuffer,
void* uncompressedDataBuffer);
private:
// AbstractDataWriter
virtual status_t WriteDataNoThrow(const void* buffer,
size_t size);
private:
struct Chunk;
struct ChunkSegment;
struct ChunkBuffer;
private:
void _Uninit();
status_t _FlushPendingData();
status_t _WriteChunk(const void* data, size_t size,
bool mayCompress);
status_t _WriteDataCompressed(const void* data,
size_t size);
status_t _WriteDataUncompressed(const void* data,
size_t size);
void _PushChunks(ChunkBuffer& chunkBuffer,
uint64 startOffset, uint64 endOffset);
private:
void* fPendingDataBuffer;
void* fCompressedDataBuffer;
size_t fPendingDataSize;
Array<uint64> fOffsets;
};
} // namespace BPrivate
} // namespace BHPKG
} // namespace BPackageKit
#endif // _PACKAGE__HPKG__PRIVATE__PACKAGE_FILE_HEAP_WRITER_H_
@@ -25,8 +25,7 @@ namespace BPrivate {
class PackageReaderImpl : public ReaderImplBase {
typedef ReaderImplBase inherited;
public:
PackageReaderImpl(
BErrorOutput* errorOutput);
PackageReaderImpl(BErrorOutput* errorOutput);
~PackageReaderImpl();
status_t Init(const char* fileName);
@@ -41,13 +40,15 @@ public:
uint64 HeapOffset() const;
uint64 HeapSize() const;
PackageFileHeapReader* HeapReader() const
{ return inherited::HeapReader(); }
protected:
// from ReaderImplBase
virtual status_t ReadAttributeValue(uint8 type, uint8 encoding,
AttributeValue& _value);
private:
struct DataAttributeHandler;
struct AttributeAttributeHandler;
struct EntryAttributeHandler;
struct RootAttributeHandler;
@@ -59,11 +60,10 @@ private:
status_t _GetTOCBuffer(size_t size,
const void*& _buffer);
private:
uint64 fTotalSize;
uint64 fHeapOffset;
uint64 fHeapSize;
SectionInfo fTOCSection;
PackageFileSection fTOCSection;
};
@@ -35,6 +35,8 @@ namespace BPrivate {
struct hpkg_header;
class PackageFileHeapWriter;
class PackageWriterImpl : public WriterImplBase {
typedef WriterImplBase inherited;
@@ -78,30 +80,16 @@ private:
Entry* entry, const char* fileName,
char* pathBuffer);
void _CompactHeap();
void _MoveHeapChunk(off_t fromOffset, off_t toOffset,
off_t size);
void _AttributeRemoved(Attribute* attribute);
void _WriteTOC(hpkg_header& header);
int32 _WriteTOCCompressed(
uint64& _uncompressedStringsSize,
uint64& _uncompressedMainSize,
uint64& _tocUncompressedSize);
int32 _WriteTOCUncompressed(
uint64& _uncompressedStringsSize,
uint64& _uncompressedMainSize,
uint64& _tocUncompressedSize);
int32 _WriteTOCSections(uint64& _stringsSize,
uint64& _mainSize);
void _WriteTOC(hpkg_header& header, uint64& _length);
void _WriteAttributeChildren(Attribute* attribute);
void _WritePackageAttributes(hpkg_header& header);
void _WritePackageAttributes(hpkg_header& header,
uint64& _length);
uint32 _WritePackageAttributesCompressed(
uint32& _stringsLengthUncompressed,
uint32& _attributesLengthUncompressed);
uint32 _WritePackageAttributesUncompressed(
uint32& _stringsLengthUncompressed,
uint32& _attributesLengthUncompressed);
void _AddEntry(int dirFD, Entry* entry,
const char* fileName, char* pathBuffer);
@@ -125,8 +113,6 @@ private:
status_t _AddData(BDataReader& dataReader, off_t size);
status_t _WriteUncompressedData(BDataReader& dataReader,
off_t size, uint64 writeOffset);
status_t _WriteZlibCompressedData(
BDataReader& dataReader,
off_t size, uint64 writeOffset,
@@ -136,12 +122,9 @@ private:
BPackageWriterListener* fListener;
off_t fHeapOffset;
off_t fHeapEnd;
uint16 fHeaderSize;
::BPrivate::RangeArray<off_t>* fHeapRangesToRemove;
void* fDataBuffer;
const size_t fDataBufferSize;
::BPrivate::RangeArray<uint64>* fHeapRangesToRemove;
Entry* fRootEntry;
+294 -163
View File
@@ -7,6 +7,10 @@
#define _PACKAGE__HPKG__PRIVATE__READER_IMPL_BASE_H_
#include <errno.h>
#include <sys/stat.h>
#include <ByteOrder.h>
#include <SupportDefs.h>
#include <util/SinglyLinkedList.h>
@@ -27,176 +31,73 @@ class BErrorOutput;
namespace BPrivate {
class PackageFileHeapReader;
struct PackageFileSection {
uint32 uncompressedLength;
uint8* data;
uint64 offset;
uint64 currentOffset;
uint64 stringsLength;
uint64 stringsCount;
char** strings;
const char* name;
PackageFileSection(const char* _name)
:
data(NULL),
strings(NULL),
name(_name)
{
}
~PackageFileSection()
{
delete[] strings;
delete[] data;
}
};
class ReaderImplBase {
protected:
ReaderImplBase(
ReaderImplBase(const char* fileType,
BErrorOutput* errorOutput);
virtual ~ReaderImplBase();
virtual status_t Init(int fd, bool keepFD);
int FD() const;
BErrorOutput* ErrorOutput() const;
PackageFileHeapReader* HeapReader() const
{ return fHeapReader; }
protected:
struct AttributeHandlerContext {
BErrorOutput* errorOutput;
union {
BPackageContentHandler* packageContentHandler;
BLowLevelPackageContentHandler* lowLevelHandler;
};
bool hasLowLevelHandler;
uint64 heapOffset;
uint64 heapSize;
BHPKGPackageSectionID section;
AttributeHandlerContext(BErrorOutput* errorOutput,
BPackageContentHandler* packageContentHandler,
BHPKGPackageSectionID section);
AttributeHandlerContext(BErrorOutput* errorOutput,
BLowLevelPackageContentHandler* lowLevelHandler,
BHPKGPackageSectionID section);
void ErrorOccurred();
};
class AttributeHandlerContext;
class AttributeHandler;
class IgnoreAttributeHandler;
class PackageVersionAttributeHandler;
class PackageResolvableAttributeHandler;
class PackageResolvableExpressionAttributeHandler;
class PackageAttributeHandler;
class LowLevelAttributeHandler;
typedef BPackageAttributeValue AttributeValue;
struct AttributeHandler
: SinglyLinkedListLinkImpl<AttributeHandler> {
virtual ~AttributeHandler();
void SetLevel(int level);
virtual status_t HandleAttribute(
AttributeHandlerContext* context, uint8 id,
const AttributeValue& value, AttributeHandler** _handler);
virtual status_t Delete(AttributeHandlerContext* context);
protected:
int fLevel;
};
struct IgnoreAttributeHandler : AttributeHandler {
};
struct PackageVersionAttributeHandler : AttributeHandler {
PackageVersionAttributeHandler(
BPackageInfoAttributeValue& packageInfoValue,
BPackageVersionData& versionData, bool notify);
virtual status_t HandleAttribute(
AttributeHandlerContext* context, uint8 id,
const AttributeValue& value, AttributeHandler** _handler);
virtual status_t Delete(AttributeHandlerContext* context);
private:
BPackageInfoAttributeValue& fPackageInfoValue;
BPackageVersionData& fPackageVersionData;
bool fNotify;
};
struct PackageResolvableAttributeHandler : AttributeHandler {
PackageResolvableAttributeHandler(
BPackageInfoAttributeValue& packageInfoValue);
virtual status_t HandleAttribute(
AttributeHandlerContext* context, uint8 id,
const AttributeValue& value, AttributeHandler** _handler);
virtual status_t Delete(AttributeHandlerContext* context);
private:
BPackageInfoAttributeValue& fPackageInfoValue;
};
struct PackageResolvableExpressionAttributeHandler
: AttributeHandler {
PackageResolvableExpressionAttributeHandler(
BPackageInfoAttributeValue& packageInfoValue);
virtual status_t HandleAttribute(
AttributeHandlerContext* context, uint8 id,
const AttributeValue& value, AttributeHandler** _handler);
virtual status_t Delete(AttributeHandlerContext* context);
private:
BPackageInfoAttributeValue& fPackageInfoValue;
};
struct PackageAttributeHandler : AttributeHandler {
virtual status_t HandleAttribute(
AttributeHandlerContext* context, uint8 id,
const AttributeValue& value, AttributeHandler** _handler);
private:
BPackageInfoAttributeValue fPackageInfoValue;
};
struct LowLevelAttributeHandler : AttributeHandler {
LowLevelAttributeHandler();
LowLevelAttributeHandler(uint8 id,
const BPackageAttributeValue& value, void* parentToken,
void* token);
virtual status_t HandleAttribute(
AttributeHandlerContext* context, uint8 id,
const AttributeValue& value, AttributeHandler** _handler);
virtual status_t Delete(AttributeHandlerContext* context);
private:
void* fParentToken;
void* fToken;
uint8 fID;
AttributeValue fValue;
};
struct SectionInfo {
uint32 compression;
uint32 compressedLength;
uint32 uncompressedLength;
uint8* data;
uint64 offset;
uint64 currentOffset;
uint64 stringsLength;
uint64 stringsCount;
char** strings;
const char* name;
SectionInfo(const char* _name)
:
data(NULL),
strings(NULL),
name(_name)
{
}
~SectionInfo()
{
delete[] strings;
delete[] data;
}
};
typedef SinglyLinkedList<AttributeHandler> AttributeHandlerList;
protected:
const char* CheckCompression(
const SectionInfo& section) const;
template<typename Header, uint32 kMagic, uint16 kVersion>
status_t Init(int fd, bool keepFD, Header& header);
status_t InitHeapReader(uint32 compression,
uint32 chunkSize, off_t offset,
uint64 compressedSize,
uint64 uncompressedSize);
status_t InitSection(PackageFileSection& section,
uint64 endOffset, uint64 length,
uint64 maxSaneLength, uint64 stringsLength,
uint64 stringsCount);
status_t PrepareSection(PackageFileSection& section);
status_t ParseStrings();
@@ -214,8 +115,7 @@ protected:
status_t ReadBuffer(off_t offset, void* buffer,
size_t size);
status_t ReadCompressedBuffer(
const SectionInfo& section);
status_t ReadSection(const PackageFileSection& section);
inline AttributeHandler* CurrentAttributeHandler() const;
inline void PushAttributeHandler(
@@ -223,13 +123,15 @@ protected:
inline AttributeHandler* PopAttributeHandler();
inline void ClearAttributeHandlerStack();
inline SectionInfo* CurrentSection();
inline void SetCurrentSection(SectionInfo* section);
inline PackageFileSection* CurrentSection();
inline void SetCurrentSection(PackageFileSection* section);
protected:
SectionInfo fPackageAttributesSection;
PackageFileSection fPackageAttributesSection;
private:
status_t _Init(int fd, bool keepFD);
status_t _ParseAttributeTree(
AttributeHandlerContext* context);
@@ -247,11 +149,14 @@ private:
size_t* _stringLength = NULL);
private:
const char* fFileType;
BErrorOutput* fErrorOutput;
int fFD;
bool fOwnsFD;
SectionInfo* fCurrentSection;
PackageFileHeapReader* fHeapReader;
PackageFileSection* fCurrentSection;
AttributeHandlerList fAttributeHandlerStack;
@@ -260,6 +165,232 @@ private:
};
// #pragma mark - attribute handlers
class ReaderImplBase::AttributeHandlerContext {
public:
BErrorOutput* errorOutput;
union {
BPackageContentHandler* packageContentHandler;
BLowLevelPackageContentHandler* lowLevelHandler;
};
bool hasLowLevelHandler;
BHPKGPackageSectionID section;
public:
AttributeHandlerContext(
BErrorOutput* errorOutput,
BPackageContentHandler*
packageContentHandler,
BHPKGPackageSectionID section);
AttributeHandlerContext(
BErrorOutput* errorOutput,
BLowLevelPackageContentHandler*
lowLevelHandler,
BHPKGPackageSectionID section);
void ErrorOccurred();
};
class ReaderImplBase::AttributeHandler
: public SinglyLinkedListLinkImpl<AttributeHandler> {
public:
virtual ~AttributeHandler();
void SetLevel(int level);
virtual status_t HandleAttribute(
AttributeHandlerContext* context, uint8 id,
const AttributeValue& value,
AttributeHandler** _handler);
virtual status_t Delete(AttributeHandlerContext* context);
protected:
int fLevel;
};
class ReaderImplBase::IgnoreAttributeHandler : public AttributeHandler {
};
class ReaderImplBase::PackageVersionAttributeHandler : public AttributeHandler {
public:
PackageVersionAttributeHandler(
BPackageInfoAttributeValue&
packageInfoValue,
BPackageVersionData& versionData,
bool notify);
virtual status_t HandleAttribute(
AttributeHandlerContext* context, uint8 id,
const AttributeValue& value,
AttributeHandler** _handler);
virtual status_t Delete(AttributeHandlerContext* context);
private:
BPackageInfoAttributeValue& fPackageInfoValue;
BPackageVersionData& fPackageVersionData;
bool fNotify;
};
class ReaderImplBase::PackageResolvableAttributeHandler
: public AttributeHandler {
public:
PackageResolvableAttributeHandler(
BPackageInfoAttributeValue&
packageInfoValue);
virtual status_t HandleAttribute(
AttributeHandlerContext* context, uint8 id,
const AttributeValue& value,
AttributeHandler** _handler);
virtual status_t Delete(AttributeHandlerContext* context);
private:
BPackageInfoAttributeValue& fPackageInfoValue;
};
class ReaderImplBase::PackageResolvableExpressionAttributeHandler
: public AttributeHandler {
public:
PackageResolvableExpressionAttributeHandler(
BPackageInfoAttributeValue&
packageInfoValue);
virtual status_t HandleAttribute(
AttributeHandlerContext* context, uint8 id,
const AttributeValue& value,
AttributeHandler** _handler);
virtual status_t Delete(AttributeHandlerContext* context);
private:
BPackageInfoAttributeValue& fPackageInfoValue;
};
class ReaderImplBase::PackageAttributeHandler : public AttributeHandler {
public:
virtual status_t HandleAttribute(
AttributeHandlerContext* context, uint8 id,
const AttributeValue& value,
AttributeHandler** _handler);
private:
BPackageInfoAttributeValue fPackageInfoValue;
};
class ReaderImplBase::LowLevelAttributeHandler : public AttributeHandler {
public:
LowLevelAttributeHandler();
LowLevelAttributeHandler(uint8 id,
const BPackageAttributeValue& value,
void* parentToken, void* token);
virtual status_t HandleAttribute(
AttributeHandlerContext* context, uint8 id,
const AttributeValue& value,
AttributeHandler** _handler);
virtual status_t Delete(AttributeHandlerContext* context);
private:
void* fParentToken;
void* fToken;
uint8 fID;
AttributeValue fValue;
};
// #pragma mark - template and inline methods
template<typename Header, uint32 kMagic, uint16 kVersion>
status_t
ReaderImplBase::Init(int fd, bool keepFD, Header& header)
{
status_t error = _Init(fd, keepFD);
if (error != B_OK)
return error;
// stat the file
struct stat st;
if (fstat(FD(), &st) < 0) {
ErrorOutput()->PrintError("Error: Failed to access %s file: %s\n",
fFileType, strerror(errno));
return errno;
}
// read the header
if ((error = ReadBuffer(0, &header, sizeof(header))) != B_OK)
return error;
// check the header
// magic
if (B_BENDIAN_TO_HOST_INT32(header.magic) != kMagic) {
ErrorOutput()->PrintError("Error: Invalid %s file: Invalid "
"magic\n", fFileType);
return B_BAD_DATA;
}
// version
if (B_BENDIAN_TO_HOST_INT16(header.version) != kVersion) {
ErrorOutput()->PrintError("Error: Invalid/unsupported %s file "
"version (%d)\n", fFileType,
B_BENDIAN_TO_HOST_INT16(header.version));
return B_MISMATCHED_VALUES;
}
// header size
uint64 heapOffset = B_BENDIAN_TO_HOST_INT16(header.header_size);
if (heapOffset < (off_t)sizeof(header)) {
ErrorOutput()->PrintError("Error: Invalid %s file: Invalid header "
"size (%" B_PRIu64 ")\n", fFileType, heapOffset);
return B_BAD_DATA;
}
// total size
uint64 totalSize = B_BENDIAN_TO_HOST_INT64(header.total_size);
if (totalSize != (uint64)st.st_size) {
ErrorOutput()->PrintError("Error: Invalid %s file: Total size in "
"header (%" B_PRIu64 ") doesn't agree with total file size (%"
B_PRIdOFF ")\n", fFileType, totalSize, st.st_size);
return B_BAD_DATA;
}
// heap size
uint64 compressedHeapSize
= B_BENDIAN_TO_HOST_INT64(header.heap_size_compressed);
if (compressedHeapSize > totalSize
|| heapOffset > totalSize - compressedHeapSize) {
ErrorOutput()->PrintError("Error: Invalid %s file: Heap size in "
"header (%" B_PRIu64 ") doesn't agree with total file size (%"
B_PRIu64 ") and heap offset (%" B_PRIu64 ")\n", fFileType,
compressedHeapSize, totalSize, heapOffset);
return B_BAD_DATA;
}
error = InitHeapReader(
B_BENDIAN_TO_HOST_INT32(header.heap_compression),
B_BENDIAN_TO_HOST_INT32(header.heap_chunk_size), heapOffset,
compressedHeapSize,
B_BENDIAN_TO_HOST_INT64(header.heap_size_uncompressed));
if (error != B_OK)
return error;
return B_OK;
}
inline int
ReaderImplBase::FD() const
{
@@ -274,7 +405,7 @@ ReaderImplBase::ErrorOutput() const
}
ReaderImplBase::SectionInfo*
PackageFileSection*
ReaderImplBase::CurrentSection()
{
return fCurrentSection;
@@ -282,7 +413,7 @@ ReaderImplBase::CurrentSection()
void
ReaderImplBase::SetCurrentSection(SectionInfo* section)
ReaderImplBase::SetCurrentSection(PackageFileSection* section)
{
fCurrentSection = section;
}
@@ -25,8 +25,7 @@ namespace BPrivate {
class RepositoryReaderImpl : public ReaderImplBase {
typedef ReaderImplBase inherited;
public:
RepositoryReaderImpl(
BErrorOutput* errorOutput);
RepositoryReaderImpl(BErrorOutput* errorOutput);
~RepositoryReaderImpl();
status_t Init(const char* fileName);
@@ -42,7 +41,6 @@ private:
struct RootAttributeHandler;
private:
SectionInfo fRepositoryInfoSection;
BRepositoryInfo fRepositoryInfo;
};
@@ -50,10 +50,9 @@ private:
status_t _RegisterCurrentPackageInfo();
status_t _WriteRepositoryInfo(hpkg_repo_header& header,
ssize_t& _infoLengthCompressed);
off_t _WritePackageAttributes(
hpkg_repo_header& header, off_t startOffset,
ssize_t& _packagesLengthCompressed);
uint64& _length);
void _WritePackageAttributes(
hpkg_repo_header& header, uint64& _length);
struct PackageNameSet;
+26 -101
View File
@@ -11,6 +11,7 @@
#include <package/hpkg/HPKGDefsPrivate.h>
#include <package/hpkg/DataOutput.h>
#include <package/hpkg/DataWriters.h>
#include <package/hpkg/Strings.h>
#include <package/hpkg/ZlibCompressor.h>
@@ -29,16 +30,19 @@ class BErrorOutput;
namespace BPrivate {
class AbstractDataWriter;
class PackageFileHeapWriter;
struct hpkg_header;
class WriterImplBase {
public:
WriterImplBase(BErrorOutput* errorOutput);
WriterImplBase(const char* fileType,
BErrorOutput* errorOutput);
~WriterImplBase();
protected:
struct AttributeValue {
union {
int64 signedInt;
@@ -92,63 +96,10 @@ protected:
void _DeleteChildren();
};
struct AbstractDataWriter {
AbstractDataWriter();
virtual ~AbstractDataWriter();
uint64 BytesWritten() const;
virtual status_t WriteDataNoThrow(const void* buffer,
size_t size) = 0;
void WriteDataThrows(const void* buffer, size_t size);
protected:
uint64 fBytesWritten;
};
struct FDDataWriter : AbstractDataWriter {
FDDataWriter(int fd, off_t offset, BErrorOutput* errorOutput);
virtual status_t WriteDataNoThrow(const void* buffer,
size_t size);
off_t Offset() const;
private:
int fFD;
off_t fOffset;
BErrorOutput* fErrorOutput;
};
struct ZlibDataWriter : AbstractDataWriter, private BDataOutput {
ZlibDataWriter(AbstractDataWriter* dataWriter);
void Init();
void Finish();
virtual status_t WriteDataNoThrow(const void* buffer,
size_t size);
private:
// BDataOutput
virtual status_t WriteData(const void* buffer, size_t size);
private:
AbstractDataWriter* fDataWriter;
ZlibCompressor fCompressor;
};
typedef DoublyLinkedList<PackageAttribute> PackageAttributeList;
protected:
status_t Init(const char* fileName, const char* type,
uint32 flags);
status_t Init(const char* fileName, uint32 flags);
void RegisterPackageInfo(
PackageAttributeList& attributeList,
@@ -180,13 +131,16 @@ protected:
void WriteAttributeValue(const AttributeValue& value,
uint8 encoding);
void WriteUnsignedLEB128(uint64 value);
inline void WriteString(const char* string);
template<typename Type>
inline void Write(const Type& value);
inline void WriteString(const char* string);
inline void WriteBuffer(const void* data, size_t size);
// appends data to the heap
void WriteBuffer(const void* buffer, size_t size,
void RawWriteBuffer(const void* buffer, size_t size,
off_t offset);
// writes to the file directly
inline int FD() const;
inline uint32 Flags() const;
@@ -197,11 +151,11 @@ protected:
inline const StringCache& PackageStringCache() const;
inline StringCache& PackageStringCache();
inline AbstractDataWriter* DataWriter() const;
inline void SetDataWriter(AbstractDataWriter* dataWriter);
inline void SetFinished(bool finished);
protected:
PackageFileHeapWriter* fHeapWriter;
private:
static const BHPKGAttributeID kDefaultVersionAttributeID
= B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR;
@@ -211,6 +165,7 @@ private:
const PackageAttributeList& attributes);
private:
const char* fFileType;
BErrorOutput* fErrorOutput;
const char* fFileName;
uint32 fFlags;
@@ -224,41 +179,25 @@ private:
};
inline uint64
WriterImplBase::AbstractDataWriter::BytesWritten() const
{
return fBytesWritten;
}
inline void
WriterImplBase::AbstractDataWriter::WriteDataThrows(const void* buffer,
size_t size)
{
status_t error = WriteDataNoThrow(buffer, size);
if (error != B_OK)
throw status_t(error);
}
inline off_t
WriterImplBase::FDDataWriter::Offset() const
{
return fOffset;
}
template<typename Type>
inline void
WriterImplBase::Write(const Type& value)
{
fDataWriter->WriteDataThrows(&value, sizeof(Type));
WriteBuffer(&value, sizeof(Type));
}
inline void
WriterImplBase::WriteString(const char* string)
{
fDataWriter->WriteDataThrows(string, strlen(string) + 1);
WriteBuffer(string, strlen(string) + 1);
}
inline void
WriterImplBase::WriteBuffer(const void* data, size_t size)
{
fDataWriter->WriteDataThrows(data, size);
}
@@ -276,20 +215,6 @@ WriterImplBase::Flags() const
}
inline WriterImplBase::AbstractDataWriter*
WriterImplBase::DataWriter() const
{
return fDataWriter;
}
inline void
WriterImplBase::SetDataWriter(AbstractDataWriter* dataWriter)
{
fDataWriter = dataWriter;
}
inline const WriterImplBase::PackageAttributeList&
WriterImplBase::PackageAttributes() const
{