PackageWriterImpl.cpp revision b08627f3
15fb1c6ffSOliver Tappe/* 232832cbeSIngo Weinhold * Copyright 2009-2014, Ingo Weinhold, ingo_weinhold@gmx.de. 3fd9c0b33SOliver Tappe * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de> 45fb1c6ffSOliver Tappe * Distributed under the terms of the MIT License. 55fb1c6ffSOliver Tappe */ 65fb1c6ffSOliver Tappe 75fb1c6ffSOliver Tappe 85fb1c6ffSOliver Tappe#include <package/hpkg/PackageWriterImpl.h> 95fb1c6ffSOliver Tappe 105fb1c6ffSOliver Tappe#include <dirent.h> 115fb1c6ffSOliver Tappe#include <errno.h> 125fb1c6ffSOliver Tappe#include <fcntl.h> 135fb1c6ffSOliver Tappe#include <stdio.h> 145fb1c6ffSOliver Tappe#include <stdlib.h> 155fb1c6ffSOliver Tappe#include <string.h> 165fb1c6ffSOliver Tappe#include <sys/stat.h> 175fb1c6ffSOliver Tappe#include <unistd.h> 185fb1c6ffSOliver Tappe 195fb1c6ffSOliver Tappe#include <algorithm> 205fb1c6ffSOliver Tappe#include <new> 215fb1c6ffSOliver Tappe 225fb1c6ffSOliver Tappe#include <ByteOrder.h> 23d77c6cd2SOliver Tappe#include <Directory.h> 247fd711efSOliver Tappe#include <Entry.h> 25d77c6cd2SOliver Tappe#include <FindDirectory.h> 265fb1c6ffSOliver Tappe#include <fs_attr.h> 27d77c6cd2SOliver Tappe#include <Path.h> 285fb1c6ffSOliver Tappe 290ee16518SIngo Weinhold#include <package/hpkg/BlockBufferPoolNoLock.h> 3000bc8e9cSIngo Weinhold#include <package/hpkg/PackageAttributeValue.h> 3100bc8e9cSIngo Weinhold#include <package/hpkg/PackageContentHandler.h> 3200bc8e9cSIngo Weinhold#include <package/hpkg/PackageData.h> 3300bc8e9cSIngo Weinhold#include <package/hpkg/PackageDataReader.h> 3400bc8e9cSIngo Weinhold 355fb1c6ffSOliver Tappe#include <AutoDeleter.h> 3600bc8e9cSIngo Weinhold#include <RangeArray.h> 375fb1c6ffSOliver Tappe 3833bc4425SOliver Tappe#include <package/hpkg/HPKGDefsPrivate.h> 395fb1c6ffSOliver Tappe 405fb1c6ffSOliver Tappe#include <package/hpkg/DataReader.h> 41cdfeba5aSIngo Weinhold#include <package/hpkg/PackageFileHeapReader.h> 421f633814SIngo Weinhold#include <package/hpkg/PackageFileHeapWriter.h> 4300bc8e9cSIngo Weinhold#include <package/hpkg/PackageReaderImpl.h> 445fb1c6ffSOliver Tappe#include <package/hpkg/Stacker.h> 455fb1c6ffSOliver Tappe 465fb1c6ffSOliver Tappe 4715a5c3f7SOliver Tappeusing BPrivate::FileDescriptorCloser; 4815a5c3f7SOliver Tappe 4915a5c3f7SOliver Tappe 507ea4dbceSIngo Weinholdstatic const char* const kPublicDomainLicenseName = "Public Domain"; 517ea4dbceSIngo Weinhold 527ea4dbceSIngo Weinhold 5385e13d1eSIngo Weinhold#include <typeinfo> 54caa4217eSIngo Weinhold 555fb1c6ffSOliver Tappenamespace BPackageKit { 565fb1c6ffSOliver Tappe 575fb1c6ffSOliver Tappenamespace BHPKG { 585fb1c6ffSOliver Tappe 595fb1c6ffSOliver Tappenamespace BPrivate { 605fb1c6ffSOliver Tappe 615fb1c6ffSOliver Tappe 625fb1c6ffSOliver Tappe// #pragma mark - Attributes 635fb1c6ffSOliver Tappe 645fb1c6ffSOliver Tappe 655fb1c6ffSOliver Tappestruct PackageWriterImpl::Attribute 665fb1c6ffSOliver Tappe : public DoublyLinkedListLinkImpl<Attribute> { 6733bc4425SOliver Tappe BHPKGAttributeID id; 685fb1c6ffSOliver Tappe AttributeValue value; 695fb1c6ffSOliver Tappe DoublyLinkedList<Attribute> children; 705fb1c6ffSOliver Tappe 7133bc4425SOliver Tappe Attribute(BHPKGAttributeID id_ = B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) 725fb1c6ffSOliver Tappe : 7333bc4425SOliver Tappe id(id_) 745fb1c6ffSOliver Tappe { 755fb1c6ffSOliver Tappe } 765fb1c6ffSOliver Tappe 775fb1c6ffSOliver Tappe ~Attribute() 785fb1c6ffSOliver Tappe { 795fb1c6ffSOliver Tappe DeleteChildren(); 805fb1c6ffSOliver Tappe } 815fb1c6ffSOliver Tappe 825fb1c6ffSOliver Tappe void AddChild(Attribute* child) 835fb1c6ffSOliver Tappe { 845fb1c6ffSOliver Tappe children.Add(child); 855fb1c6ffSOliver Tappe } 865fb1c6ffSOliver Tappe 8700bc8e9cSIngo Weinhold void RemoveChild(Attribute* child) 8800bc8e9cSIngo Weinhold { 8900bc8e9cSIngo Weinhold children.Remove(child); 9000bc8e9cSIngo Weinhold } 9100bc8e9cSIngo Weinhold 925fb1c6ffSOliver Tappe void DeleteChildren() 935fb1c6ffSOliver Tappe { 945fb1c6ffSOliver Tappe while (Attribute* child = children.RemoveHead()) 955fb1c6ffSOliver Tappe delete child; 965fb1c6ffSOliver Tappe } 9700bc8e9cSIngo Weinhold 9800bc8e9cSIngo Weinhold Attribute* FindEntryChild(const char* fileName) const 9900bc8e9cSIngo Weinhold { 10000bc8e9cSIngo Weinhold for (DoublyLinkedList<Attribute>::ConstIterator it 10100bc8e9cSIngo Weinhold = children.GetIterator(); Attribute* child = it.Next();) { 10200bc8e9cSIngo Weinhold if (child->id != B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY) 10300bc8e9cSIngo Weinhold continue; 10400bc8e9cSIngo Weinhold if (child->value.type != B_HPKG_ATTRIBUTE_TYPE_STRING) 10500bc8e9cSIngo Weinhold continue; 10600bc8e9cSIngo Weinhold const char* childName = child->value.string->string; 10700bc8e9cSIngo Weinhold if (strcmp(fileName, childName) == 0) 10800bc8e9cSIngo Weinhold return child; 10900bc8e9cSIngo Weinhold } 11000bc8e9cSIngo Weinhold 11100bc8e9cSIngo Weinhold return NULL; 11200bc8e9cSIngo Weinhold } 11300bc8e9cSIngo Weinhold 11400bc8e9cSIngo Weinhold Attribute* FindEntryChild(const char* fileName, size_t nameLength) const 11500bc8e9cSIngo Weinhold { 11600bc8e9cSIngo Weinhold BString name(fileName, nameLength); 11700bc8e9cSIngo Weinhold return (size_t)name.Length() == nameLength 11800bc8e9cSIngo Weinhold ? FindEntryChild(name) : NULL; 11900bc8e9cSIngo Weinhold } 12000bc8e9cSIngo Weinhold 12100bc8e9cSIngo Weinhold Attribute* FindNodeAttributeChild(const char* attributeName) const 12200bc8e9cSIngo Weinhold { 12300bc8e9cSIngo Weinhold for (DoublyLinkedList<Attribute>::ConstIterator it 12400bc8e9cSIngo Weinhold = children.GetIterator(); Attribute* child = it.Next();) { 12500bc8e9cSIngo Weinhold if (child->id != B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE) 12600bc8e9cSIngo Weinhold continue; 12700bc8e9cSIngo Weinhold if (child->value.type != B_HPKG_ATTRIBUTE_TYPE_STRING) 12800bc8e9cSIngo Weinhold continue; 12900bc8e9cSIngo Weinhold const char* childName = child->value.string->string; 13000bc8e9cSIngo Weinhold if (strcmp(attributeName, childName) == 0) 13100bc8e9cSIngo Weinhold return child; 13200bc8e9cSIngo Weinhold } 13300bc8e9cSIngo Weinhold 13400bc8e9cSIngo Weinhold return NULL; 13500bc8e9cSIngo Weinhold } 13600bc8e9cSIngo Weinhold 13700bc8e9cSIngo Weinhold Attribute* ChildWithID(BHPKGAttributeID id) const 13800bc8e9cSIngo Weinhold { 13900bc8e9cSIngo Weinhold for (DoublyLinkedList<Attribute>::ConstIterator it 14000bc8e9cSIngo Weinhold = children.GetIterator(); Attribute* child = it.Next();) { 14100bc8e9cSIngo Weinhold if (child->id == id) 14200bc8e9cSIngo Weinhold return child; 14300bc8e9cSIngo Weinhold } 14400bc8e9cSIngo Weinhold 14500bc8e9cSIngo Weinhold return NULL; 14600bc8e9cSIngo Weinhold } 14700bc8e9cSIngo Weinhold}; 14800bc8e9cSIngo Weinhold 14900bc8e9cSIngo Weinhold 15000bc8e9cSIngo Weinhold// #pragma mark - PackageContentHandler 15100bc8e9cSIngo Weinhold 15200bc8e9cSIngo Weinhold 15300bc8e9cSIngo Weinholdstruct PackageWriterImpl::PackageContentHandler 15400bc8e9cSIngo Weinhold : BLowLevelPackageContentHandler { 15500bc8e9cSIngo Weinhold PackageContentHandler(Attribute* rootAttribute, BErrorOutput* errorOutput, 1561f633814SIngo Weinhold StringCache& stringCache) 15700bc8e9cSIngo Weinhold : 15800bc8e9cSIngo Weinhold fErrorOutput(errorOutput), 15900bc8e9cSIngo Weinhold fStringCache(stringCache), 16000bc8e9cSIngo Weinhold fRootAttribute(rootAttribute), 16100bc8e9cSIngo Weinhold fErrorOccurred(false) 16200bc8e9cSIngo Weinhold { 16300bc8e9cSIngo Weinhold } 16400bc8e9cSIngo Weinhold 16500bc8e9cSIngo Weinhold virtual status_t HandleSectionStart(BHPKGPackageSectionID sectionID, 16600bc8e9cSIngo Weinhold bool& _handleSection) 16700bc8e9cSIngo Weinhold { 16800bc8e9cSIngo Weinhold // we're only interested in the TOC 16900bc8e9cSIngo Weinhold _handleSection = sectionID == B_HPKG_SECTION_PACKAGE_TOC; 17000bc8e9cSIngo Weinhold return B_OK; 17100bc8e9cSIngo Weinhold } 17200bc8e9cSIngo Weinhold 17300bc8e9cSIngo Weinhold virtual status_t HandleSectionEnd(BHPKGPackageSectionID sectionID) 17400bc8e9cSIngo Weinhold { 17500bc8e9cSIngo Weinhold return B_OK; 17600bc8e9cSIngo Weinhold } 17700bc8e9cSIngo Weinhold 17800bc8e9cSIngo Weinhold virtual status_t HandleAttribute(BHPKGAttributeID attributeID, 17900bc8e9cSIngo Weinhold const BPackageAttributeValue& value, void* parentToken, void*& _token) 18000bc8e9cSIngo Weinhold { 18100bc8e9cSIngo Weinhold if (fErrorOccurred) 18200bc8e9cSIngo Weinhold return B_OK; 18300bc8e9cSIngo Weinhold 18400bc8e9cSIngo Weinhold Attribute* parentAttribute = parentToken != NULL 18500bc8e9cSIngo Weinhold ? (Attribute*)parentToken : fRootAttribute; 18600bc8e9cSIngo Weinhold 18700bc8e9cSIngo Weinhold Attribute* attribute = new Attribute(attributeID); 18800bc8e9cSIngo Weinhold parentAttribute->AddChild(attribute); 18900bc8e9cSIngo Weinhold 19000bc8e9cSIngo Weinhold switch (value.type) { 19100bc8e9cSIngo Weinhold case B_HPKG_ATTRIBUTE_TYPE_INT: 19200bc8e9cSIngo Weinhold attribute->value.SetTo(value.signedInt); 19300bc8e9cSIngo Weinhold break; 19400bc8e9cSIngo Weinhold 19500bc8e9cSIngo Weinhold case B_HPKG_ATTRIBUTE_TYPE_UINT: 19600bc8e9cSIngo Weinhold attribute->value.SetTo(value.unsignedInt); 19700bc8e9cSIngo Weinhold break; 19800bc8e9cSIngo Weinhold 19900bc8e9cSIngo Weinhold case B_HPKG_ATTRIBUTE_TYPE_STRING: 20000bc8e9cSIngo Weinhold { 20100bc8e9cSIngo Weinhold CachedString* string = fStringCache.Get(value.string); 20200bc8e9cSIngo Weinhold if (string == NULL) 20300bc8e9cSIngo Weinhold throw std::bad_alloc(); 20400bc8e9cSIngo Weinhold attribute->value.SetTo(string); 20500bc8e9cSIngo Weinhold break; 20600bc8e9cSIngo Weinhold } 20700bc8e9cSIngo Weinhold 20800bc8e9cSIngo Weinhold case B_HPKG_ATTRIBUTE_TYPE_RAW: 20900bc8e9cSIngo Weinhold if (value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) { 21000bc8e9cSIngo Weinhold attribute->value.SetToData(value.data.size, 2111f633814SIngo Weinhold value.data.offset); 21200bc8e9cSIngo Weinhold } else if (value.encoding 21300bc8e9cSIngo Weinhold == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) { 21400bc8e9cSIngo Weinhold attribute->value.SetToData(value.data.size, value.data.raw); 21500bc8e9cSIngo Weinhold } else { 21600bc8e9cSIngo Weinhold fErrorOutput->PrintError("Invalid attribute value encoding " 21700bc8e9cSIngo Weinhold "%d (attribute %d)\n", value.encoding, attributeID); 21800bc8e9cSIngo Weinhold return B_BAD_DATA; 21900bc8e9cSIngo Weinhold } 22000bc8e9cSIngo Weinhold break; 22100bc8e9cSIngo Weinhold 22200bc8e9cSIngo Weinhold case B_HPKG_ATTRIBUTE_TYPE_INVALID: 22300bc8e9cSIngo Weinhold default: 22400bc8e9cSIngo Weinhold fErrorOutput->PrintError("Invalid attribute value type %d " 22500bc8e9cSIngo Weinhold "(attribute %d)\n", value.type, attributeID); 22600bc8e9cSIngo Weinhold return B_BAD_DATA; 22700bc8e9cSIngo Weinhold } 22800bc8e9cSIngo Weinhold 22900bc8e9cSIngo Weinhold _token = attribute; 23000bc8e9cSIngo Weinhold return B_OK; 23100bc8e9cSIngo Weinhold } 23200bc8e9cSIngo Weinhold 23300bc8e9cSIngo Weinhold virtual status_t HandleAttributeDone(BHPKGAttributeID attributeID, 23400bc8e9cSIngo Weinhold const BPackageAttributeValue& value, void* parentToken, void* token) 23500bc8e9cSIngo Weinhold { 23600bc8e9cSIngo Weinhold return B_OK; 23700bc8e9cSIngo Weinhold } 23800bc8e9cSIngo Weinhold 23900bc8e9cSIngo Weinhold virtual void HandleErrorOccurred() 24000bc8e9cSIngo Weinhold { 24100bc8e9cSIngo Weinhold fErrorOccurred = true; 24200bc8e9cSIngo Weinhold } 24300bc8e9cSIngo Weinhold 24400bc8e9cSIngo Weinholdprivate: 24500bc8e9cSIngo Weinhold BErrorOutput* fErrorOutput; 24600bc8e9cSIngo Weinhold StringCache& fStringCache; 24700bc8e9cSIngo Weinhold Attribute* fRootAttribute; 24800bc8e9cSIngo Weinhold bool fErrorOccurred; 2495fb1c6ffSOliver Tappe}; 2505fb1c6ffSOliver Tappe 2515fb1c6ffSOliver Tappe 252f2022173SOliver Tappe// #pragma mark - Entry 2535fb1c6ffSOliver Tappe 2545fb1c6ffSOliver Tappe 2555fb1c6ffSOliver Tappestruct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl<Entry> { 2560f9a98a4SIngo Weinhold Entry(char* name, size_t nameLength, int fd, bool isImplicit) 2575fb1c6ffSOliver Tappe : 2585fb1c6ffSOliver Tappe fName(name), 2595fb1c6ffSOliver Tappe fNameLength(nameLength), 2600f9a98a4SIngo Weinhold fFD(fd), 2615fb1c6ffSOliver Tappe fIsImplicit(isImplicit) 2625fb1c6ffSOliver Tappe { 2635fb1c6ffSOliver Tappe } 2645fb1c6ffSOliver Tappe 2655fb1c6ffSOliver Tappe ~Entry() 2665fb1c6ffSOliver Tappe { 2675fb1c6ffSOliver Tappe DeleteChildren(); 2685fb1c6ffSOliver Tappe free(fName); 2695fb1c6ffSOliver Tappe } 2705fb1c6ffSOliver Tappe 2710f9a98a4SIngo Weinhold static Entry* Create(const char* name, size_t nameLength, int fd, 2720f9a98a4SIngo Weinhold bool isImplicit) 2735fb1c6ffSOliver Tappe { 2745fb1c6ffSOliver Tappe char* clonedName = (char*)malloc(nameLength + 1); 2755fb1c6ffSOliver Tappe if (clonedName == NULL) 2765fb1c6ffSOliver Tappe throw std::bad_alloc(); 2775fb1c6ffSOliver Tappe memcpy(clonedName, name, nameLength); 2785fb1c6ffSOliver Tappe clonedName[nameLength] = '\0'; 2795fb1c6ffSOliver Tappe 2800f9a98a4SIngo Weinhold Entry* entry = new(std::nothrow) Entry(clonedName, nameLength, fd, 2815fb1c6ffSOliver Tappe isImplicit); 2825fb1c6ffSOliver Tappe if (entry == NULL) { 2835fb1c6ffSOliver Tappe free(clonedName); 2845fb1c6ffSOliver Tappe throw std::bad_alloc(); 2855fb1c6ffSOliver Tappe } 2865fb1c6ffSOliver Tappe 2875fb1c6ffSOliver Tappe return entry; 2885fb1c6ffSOliver Tappe } 2895fb1c6ffSOliver Tappe 2905fb1c6ffSOliver Tappe const char* Name() const 2915fb1c6ffSOliver Tappe { 2925fb1c6ffSOliver Tappe return fName; 2935fb1c6ffSOliver Tappe } 2945fb1c6ffSOliver Tappe 2950f9a98a4SIngo Weinhold int FD() const 2960f9a98a4SIngo Weinhold { 2970f9a98a4SIngo Weinhold return fFD; 2980f9a98a4SIngo Weinhold } 2990f9a98a4SIngo Weinhold 3000f9a98a4SIngo Weinhold void SetFD(int fd) 3010f9a98a4SIngo Weinhold { 3020f9a98a4SIngo Weinhold fFD = fd; 3030f9a98a4SIngo Weinhold } 3040f9a98a4SIngo Weinhold 3055fb1c6ffSOliver Tappe bool IsImplicit() const 3065fb1c6ffSOliver Tappe { 3075fb1c6ffSOliver Tappe return fIsImplicit; 3085fb1c6ffSOliver Tappe } 3095fb1c6ffSOliver Tappe 3105fb1c6ffSOliver Tappe void SetImplicit(bool isImplicit) 3115fb1c6ffSOliver Tappe { 3125fb1c6ffSOliver Tappe fIsImplicit = isImplicit; 3135fb1c6ffSOliver Tappe } 3145fb1c6ffSOliver Tappe 3155fb1c6ffSOliver Tappe bool HasName(const char* name, size_t nameLength) 3165fb1c6ffSOliver Tappe { 3175fb1c6ffSOliver Tappe return nameLength == fNameLength 3185fb1c6ffSOliver Tappe && strncmp(name, fName, nameLength) == 0; 3195fb1c6ffSOliver Tappe } 3205fb1c6ffSOliver Tappe 3215fb1c6ffSOliver Tappe void AddChild(Entry* child) 3225fb1c6ffSOliver Tappe { 3235fb1c6ffSOliver Tappe fChildren.Add(child); 3245fb1c6ffSOliver Tappe } 3255fb1c6ffSOliver Tappe 3265fb1c6ffSOliver Tappe void DeleteChildren() 3275fb1c6ffSOliver Tappe { 3285fb1c6ffSOliver Tappe while (Entry* child = fChildren.RemoveHead()) 3295fb1c6ffSOliver Tappe delete child; 3305fb1c6ffSOliver Tappe } 3315fb1c6ffSOliver Tappe 3325fb1c6ffSOliver Tappe Entry* GetChild(const char* name, size_t nameLength) const 3335fb1c6ffSOliver Tappe { 3345fb1c6ffSOliver Tappe EntryList::ConstIterator it = fChildren.GetIterator(); 3355fb1c6ffSOliver Tappe while (Entry* child = it.Next()) { 3365fb1c6ffSOliver Tappe if (child->HasName(name, nameLength)) 3375fb1c6ffSOliver Tappe return child; 3385fb1c6ffSOliver Tappe } 3395fb1c6ffSOliver Tappe 3405fb1c6ffSOliver Tappe return NULL; 3415fb1c6ffSOliver Tappe } 3425fb1c6ffSOliver Tappe 3435fb1c6ffSOliver Tappe EntryList::ConstIterator ChildIterator() const 3445fb1c6ffSOliver Tappe { 3455fb1c6ffSOliver Tappe return fChildren.GetIterator(); 3465fb1c6ffSOliver Tappe } 3475fb1c6ffSOliver Tappe 3485fb1c6ffSOliver Tappeprivate: 3495fb1c6ffSOliver Tappe char* fName; 3505fb1c6ffSOliver Tappe size_t fNameLength; 3510f9a98a4SIngo Weinhold int fFD; 3525fb1c6ffSOliver Tappe bool fIsImplicit; 3535fb1c6ffSOliver Tappe EntryList fChildren; 3545fb1c6ffSOliver Tappe}; 3555fb1c6ffSOliver Tappe 3565fb1c6ffSOliver Tappe 357f2022173SOliver Tappe// #pragma mark - SubPathAdder 3585fb1c6ffSOliver Tappe 3595fb1c6ffSOliver Tappe 3607fd711efSOliver Tappestruct PackageWriterImpl::SubPathAdder { 3618524dd36SIngo Weinhold SubPathAdder(BErrorOutput* errorOutput, char* pathBuffer, 3628524dd36SIngo Weinhold const char* subPath) 3638524dd36SIngo Weinhold : 3648524dd36SIngo Weinhold fOriginalPathEnd(pathBuffer + strlen(pathBuffer)) 3657fd711efSOliver Tappe { 3668524dd36SIngo Weinhold if (fOriginalPathEnd != pathBuffer) 3678524dd36SIngo Weinhold strlcat(pathBuffer, "/", B_PATH_NAME_LENGTH); 3688524dd36SIngo Weinhold 3698524dd36SIngo Weinhold if (strlcat(pathBuffer, subPath, B_PATH_NAME_LENGTH) 3708524dd36SIngo Weinhold >= B_PATH_NAME_LENGTH) { 3718524dd36SIngo Weinhold *fOriginalPathEnd = '\0'; 3728524dd36SIngo Weinhold errorOutput->PrintError("Path too long: \"%s/%s\"\n", pathBuffer, 3738524dd36SIngo Weinhold subPath); 3748524dd36SIngo Weinhold throw status_t(B_BUFFER_OVERFLOW); 3758524dd36SIngo Weinhold } 3767fd711efSOliver Tappe } 3777fd711efSOliver Tappe 3787fd711efSOliver Tappe ~SubPathAdder() 3797fd711efSOliver Tappe { 3807fd711efSOliver Tappe *fOriginalPathEnd = '\0'; 3817fd711efSOliver Tappe } 3828524dd36SIngo Weinhold 3837fd711efSOliver Tappeprivate: 3847fd711efSOliver Tappe char* fOriginalPathEnd; 3857fd711efSOliver Tappe}; 3867fd711efSOliver Tappe 3877fd711efSOliver Tappe 38821ee6d5cSIngo Weinhold// #pragma mark - HeapAttributeOffsetter 38921ee6d5cSIngo Weinhold 39021ee6d5cSIngo Weinhold 39100bc8e9cSIngo Weinholdstruct PackageWriterImpl::HeapAttributeOffsetter { 3921f633814SIngo Weinhold HeapAttributeOffsetter(const RangeArray<uint64>& ranges, 3931f633814SIngo Weinhold const Array<uint64>& deltas) 39400bc8e9cSIngo Weinhold : 39500bc8e9cSIngo Weinhold fRanges(ranges), 39600bc8e9cSIngo Weinhold fDeltas(deltas) 39700bc8e9cSIngo Weinhold { 39800bc8e9cSIngo Weinhold } 39900bc8e9cSIngo Weinhold 40000bc8e9cSIngo Weinhold void ProcessAttribute(Attribute* attribute) 40100bc8e9cSIngo Weinhold { 40200bc8e9cSIngo Weinhold // If the attribute refers to a heap value, adjust it 40300bc8e9cSIngo Weinhold AttributeValue& value = attribute->value; 40400bc8e9cSIngo Weinhold 40500bc8e9cSIngo Weinhold if (value.type == B_HPKG_ATTRIBUTE_TYPE_RAW 40600bc8e9cSIngo Weinhold && value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) { 4071f633814SIngo Weinhold uint64 delta = fDeltas[fRanges.InsertionIndex(value.data.offset)]; 40800bc8e9cSIngo Weinhold value.data.offset -= delta; 40900bc8e9cSIngo Weinhold } 41000bc8e9cSIngo Weinhold 41100bc8e9cSIngo Weinhold // recurse 41200bc8e9cSIngo Weinhold for (DoublyLinkedList<Attribute>::Iterator it 41300bc8e9cSIngo Weinhold = attribute->children.GetIterator(); 41400bc8e9cSIngo Weinhold Attribute* child = it.Next();) { 41500bc8e9cSIngo Weinhold ProcessAttribute(child); 41600bc8e9cSIngo Weinhold } 41700bc8e9cSIngo Weinhold } 41800bc8e9cSIngo Weinhold 41900bc8e9cSIngo Weinholdprivate: 4201f633814SIngo Weinhold const RangeArray<uint64>& fRanges; 4211f633814SIngo Weinhold const Array<uint64>& fDeltas; 42200bc8e9cSIngo Weinhold}; 42300bc8e9cSIngo Weinhold 42400bc8e9cSIngo Weinhold 4255fb1c6ffSOliver Tappe// #pragma mark - PackageWriterImpl (Inline Methods) 4265fb1c6ffSOliver Tappe 4275fb1c6ffSOliver Tappe 4285fb1c6ffSOliver Tappetemplate<typename Type> 4295fb1c6ffSOliver Tappeinline PackageWriterImpl::Attribute* 43033bc4425SOliver TappePackageWriterImpl::_AddAttribute(BHPKGAttributeID attributeID, Type value) 4315fb1c6ffSOliver Tappe{ 4325fb1c6ffSOliver Tappe AttributeValue attributeValue; 4335fb1c6ffSOliver Tappe attributeValue.SetTo(value); 43433bc4425SOliver Tappe return _AddAttribute(attributeID, attributeValue); 4355fb1c6ffSOliver Tappe} 4365fb1c6ffSOliver Tappe 4375fb1c6ffSOliver Tappe 4385fb1c6ffSOliver Tappe// #pragma mark - PackageWriterImpl 4395fb1c6ffSOliver Tappe 4405fb1c6ffSOliver Tappe 4417fd711efSOliver TappePackageWriterImpl::PackageWriterImpl(BPackageWriterListener* listener) 4425fb1c6ffSOliver Tappe : 4431f633814SIngo Weinhold inherited("package", listener), 4447fd711efSOliver Tappe fListener(listener), 44500bc8e9cSIngo Weinhold fHeapRangesToRemove(NULL), 4465fb1c6ffSOliver Tappe fRootEntry(NULL), 4475fb1c6ffSOliver Tappe fRootAttribute(NULL), 4487efa133cSIngo Weinhold fTopAttribute(NULL), 4497efa133cSIngo Weinhold fCheckLicenses(true) 4505fb1c6ffSOliver Tappe{ 4515fb1c6ffSOliver Tappe} 4525fb1c6ffSOliver Tappe 4535fb1c6ffSOliver Tappe 4545fb1c6ffSOliver TappePackageWriterImpl::~PackageWriterImpl() 4555fb1c6ffSOliver Tappe{ 456c9ed1ea2SIngo Weinhold delete fHeapRangesToRemove; 4575fb1c6ffSOliver Tappe delete fRootAttribute; 4585fb1c6ffSOliver Tappe delete fRootEntry; 4595fb1c6ffSOliver Tappe} 4605fb1c6ffSOliver Tappe 4615fb1c6ffSOliver Tappe 4625fb1c6ffSOliver Tappestatus_t 463796343edSIngo WeinholdPackageWriterImpl::Init(const char* fileName, 464796343edSIngo Weinhold const BPackageWriterParameters& parameters) 4655fb1c6ffSOliver Tappe{ 4665fb1c6ffSOliver Tappe try { 46744c47711SIngo Weinhold return _Init(NULL, false, fileName, parameters); 46844c47711SIngo Weinhold } catch (status_t error) { 46944c47711SIngo Weinhold return error; 470b08627f3SMurai Takashi } catch (std::bad_alloc&) { 47144c47711SIngo Weinhold fListener->PrintError("Out of memory!\n"); 47244c47711SIngo Weinhold return B_NO_MEMORY; 47344c47711SIngo Weinhold } 47444c47711SIngo Weinhold} 47544c47711SIngo Weinhold 47644c47711SIngo Weinhold 47744c47711SIngo Weinholdstatus_t 47844c47711SIngo WeinholdPackageWriterImpl::Init(BPositionIO* file, bool keepFile, 47944c47711SIngo Weinhold const BPackageWriterParameters& parameters) 48044c47711SIngo Weinhold{ 48144c47711SIngo Weinhold try { 48244c47711SIngo Weinhold return _Init(file, keepFile, NULL, parameters); 4835fb1c6ffSOliver Tappe } catch (status_t error) { 4845fb1c6ffSOliver Tappe return error; 485b08627f3SMurai Takashi } catch (std::bad_alloc&) { 4867fd711efSOliver Tappe fListener->PrintError("Out of memory!\n"); 4875fb1c6ffSOliver Tappe return B_NO_MEMORY; 4885fb1c6ffSOliver Tappe } 4895fb1c6ffSOliver Tappe} 4905fb1c6ffSOliver Tappe 4915fb1c6ffSOliver Tappe 4926ae0ecd4SIngo Weinholdstatus_t 4936ae0ecd4SIngo WeinholdPackageWriterImpl::SetInstallPath(const char* installPath) 4946ae0ecd4SIngo Weinhold{ 4956ae0ecd4SIngo Weinhold fInstallPath = installPath; 4966ae0ecd4SIngo Weinhold return installPath == NULL 4976ae0ecd4SIngo Weinhold || (size_t)fInstallPath.Length() == strlen(installPath) 4986ae0ecd4SIngo Weinhold ? B_OK : B_NO_MEMORY; 4996ae0ecd4SIngo Weinhold} 5006ae0ecd4SIngo Weinhold 5016ae0ecd4SIngo Weinhold 5027efa133cSIngo Weinholdvoid 5037efa133cSIngo WeinholdPackageWriterImpl::SetCheckLicenses(bool checkLicenses) 5047efa133cSIngo Weinhold{ 5057efa133cSIngo Weinhold fCheckLicenses = checkLicenses; 5067efa133cSIngo Weinhold} 5077efa133cSIngo Weinhold 5087efa133cSIngo Weinhold 5095fb1c6ffSOliver Tappestatus_t 5100f9a98a4SIngo WeinholdPackageWriterImpl::AddEntry(const char* fileName, int fd) 5115fb1c6ffSOliver Tappe{ 5125fb1c6ffSOliver Tappe try { 5137fd711efSOliver Tappe // if it's ".PackageInfo", parse it 5147fd711efSOliver Tappe if (strcmp(fileName, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) { 5157fd711efSOliver Tappe struct ErrorListener : public BPackageInfo::ParseErrorListener { 5167fd711efSOliver Tappe ErrorListener(BPackageWriterListener* _listener) 517fc198cc3SIngo Weinhold : 518fc198cc3SIngo Weinhold listener(_listener), 519fc198cc3SIngo Weinhold errorSeen(false) 520fc198cc3SIngo Weinhold { 521fc198cc3SIngo Weinhold } 522fc198cc3SIngo Weinhold 5237fd711efSOliver Tappe virtual void OnError(const BString& msg, int line, int col) { 5247fd711efSOliver Tappe listener->PrintError("Parse error in %s(%d:%d) -> %s\n", 5257fd711efSOliver Tappe B_HPKG_PACKAGE_INFO_FILE_NAME, line, col, msg.String()); 526fc198cc3SIngo Weinhold errorSeen = true; 5277fd711efSOliver Tappe } 528fc198cc3SIngo Weinhold 5297fd711efSOliver Tappe BPackageWriterListener* listener; 530fc198cc3SIngo Weinhold bool errorSeen; 5317fd711efSOliver Tappe } errorListener(fListener); 5320f9a98a4SIngo Weinhold 5330f9a98a4SIngo Weinhold if (fd >= 0) { 5340f9a98a4SIngo Weinhold // a file descriptor is given -- read the config from there 5350f9a98a4SIngo Weinhold // stat the file to get the file size 5360f9a98a4SIngo Weinhold struct stat st; 5370f9a98a4SIngo Weinhold if (fstat(fd, &st) != 0) 5380f9a98a4SIngo Weinhold return errno; 5390f9a98a4SIngo Weinhold 5400f9a98a4SIngo Weinhold BString packageInfoString; 5410f9a98a4SIngo Weinhold char* buffer = packageInfoString.LockBuffer(st.st_size); 5420f9a98a4SIngo Weinhold if (buffer == NULL) 5430f9a98a4SIngo Weinhold return B_NO_MEMORY; 5440f9a98a4SIngo Weinhold 5450f9a98a4SIngo Weinhold ssize_t result = read_pos(fd, 0, buffer, st.st_size); 5460f9a98a4SIngo Weinhold if (result < 0) { 5470f9a98a4SIngo Weinhold packageInfoString.UnlockBuffer(0); 5480f9a98a4SIngo Weinhold return errno; 5490f9a98a4SIngo Weinhold } 5500f9a98a4SIngo Weinhold 5510f9a98a4SIngo Weinhold buffer[st.st_size] = '\0'; 5520f9a98a4SIngo Weinhold packageInfoString.UnlockBuffer(st.st_size); 5530f9a98a4SIngo Weinhold 5540f9a98a4SIngo Weinhold result = fPackageInfo.ReadFromConfigString(packageInfoString, 5550f9a98a4SIngo Weinhold &errorListener); 5560f9a98a4SIngo Weinhold if (result != B_OK) 5570f9a98a4SIngo Weinhold return result; 5580f9a98a4SIngo Weinhold } else { 5590f9a98a4SIngo Weinhold // use the file name 5600f9a98a4SIngo Weinhold BEntry packageInfoEntry(fileName); 5610f9a98a4SIngo Weinhold status_t result = fPackageInfo.ReadFromConfigFile( 5620f9a98a4SIngo Weinhold packageInfoEntry, &errorListener); 5630f9a98a4SIngo Weinhold if (result != B_OK 5640f9a98a4SIngo Weinhold || (result = fPackageInfo.InitCheck()) != B_OK) { 565fc198cc3SIngo Weinhold if (!errorListener.errorSeen) { 566fc198cc3SIngo Weinhold fListener->PrintError("Failed to read %s: %s\n", 567fc198cc3SIngo Weinhold fileName, strerror(result)); 568fc198cc3SIngo Weinhold } 5690f9a98a4SIngo Weinhold return result; 5700f9a98a4SIngo Weinhold } 5710f9a98a4SIngo Weinhold } 5727fd711efSOliver Tappe } 5737fd711efSOliver Tappe 5740f9a98a4SIngo Weinhold return _RegisterEntry(fileName, fd); 5755fb1c6ffSOliver Tappe } catch (status_t error) { 5765fb1c6ffSOliver Tappe return error; 577b08627f3SMurai Takashi } catch (std::bad_alloc&) { 5787fd711efSOliver Tappe fListener->PrintError("Out of memory!\n"); 5795fb1c6ffSOliver Tappe return B_NO_MEMORY; 5805fb1c6ffSOliver Tappe } 5815fb1c6ffSOliver Tappe} 5825fb1c6ffSOliver Tappe 5835fb1c6ffSOliver Tappe 5845fb1c6ffSOliver Tappestatus_t 5855fb1c6ffSOliver TappePackageWriterImpl::Finish() 5865fb1c6ffSOliver Tappe{ 5875fb1c6ffSOliver Tappe try { 58800bc8e9cSIngo Weinhold if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0) { 58900bc8e9cSIngo Weinhold _UpdateCheckEntryCollisions(); 59000bc8e9cSIngo Weinhold 59100bc8e9cSIngo Weinhold if (fPackageInfo.InitCheck() != B_OK) 59200bc8e9cSIngo Weinhold _UpdateReadPackageInfo(); 59300bc8e9cSIngo Weinhold } 59400bc8e9cSIngo Weinhold 595d77c6cd2SOliver Tappe if (fPackageInfo.InitCheck() != B_OK) { 5967fd711efSOliver Tappe fListener->PrintError("No package-info file found (%s)!\n", 5977fd711efSOliver Tappe B_HPKG_PACKAGE_INFO_FILE_NAME); 5987fd711efSOliver Tappe return B_BAD_DATA; 5997fd711efSOliver Tappe } 600d77c6cd2SOliver Tappe 6016ae0ecd4SIngo Weinhold fPackageInfo.SetInstallPath(fInstallPath); 6026ae0ecd4SIngo Weinhold 603e6ebdaafSIngo Weinhold RegisterPackageInfo(PackageAttributes(), fPackageInfo); 604e6ebdaafSIngo Weinhold 6057efa133cSIngo Weinhold if (fCheckLicenses) { 6067efa133cSIngo Weinhold status_t result = _CheckLicenses(); 6077efa133cSIngo Weinhold if (result != B_OK) 6087efa133cSIngo Weinhold return result; 6097efa133cSIngo Weinhold } 610d77c6cd2SOliver Tappe 61100bc8e9cSIngo Weinhold if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0) 61200bc8e9cSIngo Weinhold _CompactHeap(); 61300bc8e9cSIngo Weinhold 6145fb1c6ffSOliver Tappe return _Finish(); 6155fb1c6ffSOliver Tappe } catch (status_t error) { 6165fb1c6ffSOliver Tappe return error; 617b08627f3SMurai Takashi } catch (std::bad_alloc&) { 6187fd711efSOliver Tappe fListener->PrintError("Out of memory!\n"); 6195fb1c6ffSOliver Tappe return B_NO_MEMORY; 6205fb1c6ffSOliver Tappe } 6215fb1c6ffSOliver Tappe} 6225fb1c6ffSOliver Tappe 6235fb1c6ffSOliver Tappe 624cdfeba5aSIngo Weinholdstatus_t 625e1e6c124SIngo WeinholdPackageWriterImpl::Recompress(BPositionIO* inputFile) 626cdfeba5aSIngo Weinhold{ 627e1e6c124SIngo Weinhold if (inputFile == NULL) 628cdfeba5aSIngo Weinhold return B_BAD_VALUE; 629cdfeba5aSIngo Weinhold 630cdfeba5aSIngo Weinhold try { 631e1e6c124SIngo Weinhold return _Recompress(inputFile); 632cdfeba5aSIngo Weinhold } catch (status_t error) { 633cdfeba5aSIngo Weinhold return error; 634b08627f3SMurai Takashi } catch (std::bad_alloc&) { 635cdfeba5aSIngo Weinhold fListener->PrintError("Out of memory!\n"); 636cdfeba5aSIngo Weinhold return B_NO_MEMORY; 637cdfeba5aSIngo Weinhold } 638cdfeba5aSIngo Weinhold} 639cdfeba5aSIngo Weinhold 640cdfeba5aSIngo Weinhold 6415fb1c6ffSOliver Tappestatus_t 64244c47711SIngo WeinholdPackageWriterImpl::_Init(BPositionIO* file, bool keepFile, const char* fileName, 643796343edSIngo Weinhold const BPackageWriterParameters& parameters) 6445fb1c6ffSOliver Tappe{ 64544c47711SIngo Weinhold status_t result = inherited::Init(file, keepFile, fileName, parameters); 646f2022173SOliver Tappe if (result != B_OK) 647f2022173SOliver Tappe return result; 648f2022173SOliver Tappe 649f2022173SOliver Tappe if (fStringCache.Init() != B_OK) 6505fb1c6ffSOliver Tappe throw std::bad_alloc(); 6515fb1c6ffSOliver Tappe 6525fb1c6ffSOliver Tappe // create entry list 6530f9a98a4SIngo Weinhold fRootEntry = new Entry(NULL, 0, -1, true); 6545fb1c6ffSOliver Tappe 65533bc4425SOliver Tappe fRootAttribute = new Attribute(); 6565fb1c6ffSOliver Tappe 6571f633814SIngo Weinhold fHeapOffset = fHeaderSize = sizeof(hpkg_header); 6585fb1c6ffSOliver Tappe fTopAttribute = fRootAttribute; 6595fb1c6ffSOliver Tappe 660c9ed1ea2SIngo Weinhold fHeapRangesToRemove = new RangeArray<uint64>; 661c9ed1ea2SIngo Weinhold 66200bc8e9cSIngo Weinhold // in update mode, parse the TOC 66300bc8e9cSIngo Weinhold if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0) { 66400bc8e9cSIngo Weinhold PackageReaderImpl packageReader(fListener); 6658f5130edSIngo Weinhold hpkg_header header; 6668f5130edSIngo Weinhold result = packageReader.Init(File(), false, 0, &header); 66700bc8e9cSIngo Weinhold if (result != B_OK) 66800bc8e9cSIngo Weinhold return result; 66900bc8e9cSIngo Weinhold 67000bc8e9cSIngo Weinhold fHeapOffset = packageReader.HeapOffset(); 67100bc8e9cSIngo Weinhold 6721f633814SIngo Weinhold PackageContentHandler handler(fRootAttribute, fListener, fStringCache); 67300bc8e9cSIngo Weinhold 67400bc8e9cSIngo Weinhold result = packageReader.ParseContent(&handler); 67500bc8e9cSIngo Weinhold if (result != B_OK) 67600bc8e9cSIngo Weinhold return result; 67700bc8e9cSIngo Weinhold 6788f5130edSIngo Weinhold // While the compression level can change, we have to reuse the 6798f5130edSIngo Weinhold // compression algorithm at least. 6808f5130edSIngo Weinhold SetCompression(B_BENDIAN_TO_HOST_INT16(header.heap_compression)); 6818f5130edSIngo Weinhold 6828f5130edSIngo Weinhold result = InitHeapReader(fHeapOffset); 6838f5130edSIngo Weinhold if (result != B_OK) 6848f5130edSIngo Weinhold return result; 6858f5130edSIngo Weinhold 68646122852SIngo Weinhold fHeapWriter->Reinit(packageReader.RawHeapReader()); 687c9ed1ea2SIngo Weinhold 688c9ed1ea2SIngo Weinhold // Remove the old packages attributes and TOC section from the heap. 689c9ed1ea2SIngo Weinhold // We'll write new ones later. 690c9ed1ea2SIngo Weinhold const PackageFileSection& attributesSection 691c9ed1ea2SIngo Weinhold = packageReader.PackageAttributesSection(); 692c9ed1ea2SIngo Weinhold const PackageFileSection& tocSection = packageReader.TOCSection(); 693c9ed1ea2SIngo Weinhold if (!fHeapRangesToRemove->AddRange(attributesSection.offset, 694c9ed1ea2SIngo Weinhold attributesSection.uncompressedLength) 695c9ed1ea2SIngo Weinhold || !fHeapRangesToRemove->AddRange(tocSection.offset, 696c9ed1ea2SIngo Weinhold tocSection.uncompressedLength)) { 697c9ed1ea2SIngo Weinhold throw std::bad_alloc(); 698c9ed1ea2SIngo Weinhold } 6998f5130edSIngo Weinhold } else { 7008f5130edSIngo Weinhold result = InitHeapReader(fHeapOffset); 7018f5130edSIngo Weinhold if (result != B_OK) 7028f5130edSIngo Weinhold return result; 70300bc8e9cSIngo Weinhold } 70400bc8e9cSIngo Weinhold 7055fb1c6ffSOliver Tappe return B_OK; 7065fb1c6ffSOliver Tappe} 7075fb1c6ffSOliver Tappe 7085fb1c6ffSOliver Tappe 7092fc2aebcSIngo Weinholdstatus_t 7102fc2aebcSIngo WeinholdPackageWriterImpl::_Finish() 7112fc2aebcSIngo Weinhold{ 7122fc2aebcSIngo Weinhold // write entries 7132fc2aebcSIngo Weinhold for (EntryList::ConstIterator it = fRootEntry->ChildIterator(); 7142fc2aebcSIngo Weinhold Entry* entry = it.Next();) { 7152fc2aebcSIngo Weinhold char pathBuffer[B_PATH_NAME_LENGTH]; 7162fc2aebcSIngo Weinhold pathBuffer[0] = '\0'; 7172fc2aebcSIngo Weinhold _AddEntry(AT_FDCWD, entry, entry->Name(), pathBuffer); 7182fc2aebcSIngo Weinhold } 7192fc2aebcSIngo Weinhold 7202fc2aebcSIngo Weinhold hpkg_header header; 7212fc2aebcSIngo Weinhold 7222fc2aebcSIngo Weinhold // write the TOC and package attributes 7232fc2aebcSIngo Weinhold uint64 tocLength; 7242fc2aebcSIngo Weinhold _WriteTOC(header, tocLength); 7252fc2aebcSIngo Weinhold 7262fc2aebcSIngo Weinhold uint64 attributesLength; 7272fc2aebcSIngo Weinhold _WritePackageAttributes(header, attributesLength); 7282fc2aebcSIngo Weinhold 7292fc2aebcSIngo Weinhold // flush the heap 7302fc2aebcSIngo Weinhold status_t error = fHeapWriter->Finish(); 7312fc2aebcSIngo Weinhold if (error != B_OK) 7322fc2aebcSIngo Weinhold return error; 7332fc2aebcSIngo Weinhold 7342fc2aebcSIngo Weinhold uint64 compressedHeapSize = fHeapWriter->CompressedHeapSize(); 7352fc2aebcSIngo Weinhold 7368f5130edSIngo Weinhold header.heap_compression = B_HOST_TO_BENDIAN_INT16( 7378f5130edSIngo Weinhold Parameters().Compression()); 7382fc2aebcSIngo Weinhold header.heap_chunk_size = B_HOST_TO_BENDIAN_INT32(fHeapWriter->ChunkSize()); 7392fc2aebcSIngo Weinhold header.heap_size_compressed = B_HOST_TO_BENDIAN_INT64(compressedHeapSize); 7402fc2aebcSIngo Weinhold header.heap_size_uncompressed = B_HOST_TO_BENDIAN_INT64( 7412fc2aebcSIngo Weinhold fHeapWriter->UncompressedHeapSize()); 7422fc2aebcSIngo Weinhold 7432fc2aebcSIngo Weinhold // Truncate the file to the size it is supposed to have. In update mode, it 7442fc2aebcSIngo Weinhold // can be greater when one or more files are shrunk. In creation mode it 7452fc2aebcSIngo Weinhold // should already have the correct size. 7462fc2aebcSIngo Weinhold off_t totalSize = fHeapWriter->HeapOffset() + (off_t)compressedHeapSize; 747e527b796SIngo Weinhold error = File()->SetSize(totalSize); 748e527b796SIngo Weinhold if (error != B_OK) { 7492fc2aebcSIngo Weinhold fListener->PrintError("Failed to truncate package file to new " 7502fc2aebcSIngo Weinhold "size: %s\n", strerror(errno)); 7512fc2aebcSIngo Weinhold return errno; 7522fc2aebcSIngo Weinhold } 7532fc2aebcSIngo Weinhold 7542fc2aebcSIngo Weinhold fListener->OnPackageSizeInfo(fHeaderSize, compressedHeapSize, tocLength, 7552fc2aebcSIngo Weinhold attributesLength, totalSize); 7562fc2aebcSIngo Weinhold 7572fc2aebcSIngo Weinhold // prepare the header 7582fc2aebcSIngo Weinhold 7592fc2aebcSIngo Weinhold // general 7602fc2aebcSIngo Weinhold header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC); 7612fc2aebcSIngo Weinhold header.header_size = B_HOST_TO_BENDIAN_INT16(fHeaderSize); 7622fc2aebcSIngo Weinhold header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_VERSION); 7632fc2aebcSIngo Weinhold header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize); 7642fc2aebcSIngo Weinhold header.minor_version = B_HOST_TO_BENDIAN_INT16(B_HPKG_MINOR_VERSION); 7652fc2aebcSIngo Weinhold 7662fc2aebcSIngo Weinhold // write the header 7672fc2aebcSIngo Weinhold RawWriteBuffer(&header, sizeof(hpkg_header), 0); 768