packagefs: Add support for hpkg format V1

* Add union-like class PackageData which wraps the V1 and V2
  BPackageData classes.
* GlobalFactory: Create a data reader depending on the data format
  version.
* Package: Add a loader for V1 format and try that, if the other one
  fails.
This commit is contained in:
Ingo Weinhold
2013-05-25 01:12:24 +02:00
parent 2c32402da5
commit 11cecf980b
11 changed files with 481 additions and 43 deletions
@@ -91,7 +91,20 @@ HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES =
ZlibDecompressor.cpp
;
Includes [ FGristFiles $(HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES) ]
HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES_V1 =
HPKGDefsV1.cpp
PackageContentHandlerV1.cpp
PackageDataV1.cpp
PackageDataReaderV1.cpp
PackageEntryV1.cpp
PackageEntryAttributeV1.cpp
PackageReaderImplV1.cpp
ReaderImplBaseV1.cpp
;
Includes
[ FGristFiles $(HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES)
$(HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES_V1) ]
: [ BuildFeatureAttribute zlib : headers ] ;
local libSharedSources =
@@ -104,6 +117,7 @@ KernelAddon packagefs
$(HAIKU_PACKAGE_FS_SOURCES)
$(HAIKU_PACKAGE_FS_SHARED_SOURCES)
$(HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES)
$(HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES_V1)
$(libSharedSources)
: $(HAIKU_STATIC_LIBSUPC++) kernel_libz.a
@@ -114,5 +128,7 @@ SEARCH on [ FGristFiles $(HAIKU_PACKAGE_FS_SHARED_SOURCES) ]
+= [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] ;
SEARCH on [ FGristFiles $(HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES) ]
+= [ FDirName $(HAIKU_TOP) src kits package hpkg ] ;
SEARCH on [ FGristFiles $(HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES_V1) ]
+= [ FDirName $(HAIKU_TOP) src kits package hpkg v1 ] ;
SEARCH on [ FGristFiles $(libSharedSources) ]
+= [ FDirName $(HAIKU_TOP) src kits shared ] ;
@@ -28,7 +28,7 @@ using BPackageKit::BHPKG::BFDDataReader;
static status_t
read_package_data(const BPackageData& data, BDataReader* dataReader,
read_package_data(const PackageData& data, BDataReader* dataReader,
off_t offset, void* buffer, size_t* bufferSize)
{
// create a PackageDataReader
@@ -128,7 +128,7 @@ UnpackingAttributeCookie::ReadAttribute(PackageNode* packageNode,
PackageNodeAttribute* attribute, off_t offset, void* buffer,
size_t* bufferSize)
{
const BPackageData& data = attribute->Data();
const PackageData& data = attribute->Data();
if (data.IsEncodedInline()) {
// inline data
BBufferDataReader dataReader(data.InlineData(), data.CompressedSize());
@@ -1,5 +1,5 @@
/*
* Copyright 2009, Ingo Weinhold, [email protected].
* Copyright 2009-2013, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
@@ -8,7 +8,9 @@
#include <new>
#include <package/hpkg/HPKGDefsPrivate.h>
#include <package/hpkg/HPKGDefs.h>
#include "PackageData.h"
static const uint32 kMaxCachedBuffers = 32;
@@ -18,9 +20,13 @@ static const uint32 kMaxCachedBuffers = 32;
GlobalFactory::GlobalFactory()
:
fBufferCache(B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB, kMaxCachedBuffers),
fPackageDataReaderFactory(&fBufferCache)
fBufferCache(BPackageKit::BHPKG::B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB,
kMaxCachedBuffers),
fPackageDataReaderFactoryV1(&fBufferCache),
fPackageDataReaderFactoryV2(&fBufferCache)
{
STATIC_ASSERT((int)BPackageKit::BHPKG::B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB
== (int)BPackageKit::BHPKG::V1::B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB);
}
@@ -67,10 +73,20 @@ GlobalFactory::Default()
status_t
GlobalFactory::CreatePackageDataReader(BDataReader* dataReader,
const BPackageData& data, BAbstractBufferedDataReader*& _reader)
const PackageData& data, BAbstractBufferedDataReader*& _reader)
{
return fPackageDataReaderFactory.CreatePackageDataReader(dataReader, data,
_reader);
switch (data.Version()) {
case 1:
return fPackageDataReaderFactoryV1.CreatePackageDataReader(
dataReader, data.DataV1(), _reader);
case 2:
return fPackageDataReaderFactoryV2.CreatePackageDataReader(
dataReader, data.DataV2(), _reader);
default:
return B_NOT_SUPPORTED;
}
}
@@ -6,8 +6,8 @@
#define GLOBAL_FACTORY_H
#include <package/hpkg/HPKGDefs.h>
#include <package/hpkg/PackageDataReader.h>
#include <package/hpkg/v1/PackageDataReader.h>
#include "BlockBufferCacheKernel.h"
@@ -15,8 +15,13 @@
using BPackageKit::BHPKG::BDataReader;
using BPackageKit::BHPKG::BPackageData;
using BPackageKit::BHPKG::BAbstractBufferedDataReader;
using BPackageKit::BHPKG::BPackageDataReaderFactory;
using BPackageKit::BHPKG::B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB;
typedef BPackageKit::BHPKG::V1::BPackageDataReaderFactory
BPackageDataReaderFactoryV1;
typedef BPackageKit::BHPKG::BPackageDataReaderFactory
BPackageDataReaderFactoryV2;
class PackageData;
class GlobalFactory {
@@ -30,7 +35,7 @@ public:
static GlobalFactory* Default();
status_t CreatePackageDataReader(BDataReader* dataReader,
const BPackageData& data,
const PackageData& data,
BAbstractBufferedDataReader*& _reader);
private:
@@ -40,7 +45,8 @@ private:
static GlobalFactory* sDefaultInstance;
BlockBufferCacheKernel fBufferCache;
BPackageDataReaderFactory fPackageDataReaderFactory;
BPackageDataReaderFactoryV1 fPackageDataReaderFactoryV1;
BPackageDataReaderFactoryV2 fPackageDataReaderFactoryV2;
};
#endif // GLOBAL_FACTORY_H
@@ -17,6 +17,9 @@
#include <package/hpkg/PackageEntry.h>
#include <package/hpkg/PackageEntryAttribute.h>
#include <package/hpkg/PackageReaderImpl.h>
#include <package/hpkg/v1/PackageEntry.h>
#include <package/hpkg/v1/PackageEntryAttribute.h>
#include <package/hpkg/v1/PackageReaderImpl.h>
#include <util/AutoLock.h>
#include "DebugSupport.h"
@@ -28,8 +31,23 @@
using namespace BPackageKit;
using namespace BPackageKit::BHPKG;
using BPackageKit::BHPKG::BPrivate::PackageReaderImpl;
typedef BPackageKit::BHPKG::BErrorOutput BErrorOutput;
typedef BPackageKit::BHPKG::BPackageInfoAttributeValue
BPackageInfoAttributeValue;
typedef BPackageKit::BHPKG::BPackageVersionData BPackageVersionData;
// current format version types
typedef BPackageKit::BHPKG::BPackageContentHandler BPackageContentHandler;
typedef BPackageKit::BHPKG::BPackageEntry BPackageEntry;
typedef BPackageKit::BHPKG::BPackageEntryAttribute BPackageEntryAttribute;
typedef BPackageKit::BHPKG::BPrivate::PackageReaderImpl PackageReaderImpl;
// format version V1 types
typedef BPackageKit::BHPKG::V1::BPackageContentHandler BPackageContentHandlerV1;
typedef BPackageKit::BHPKG::V1::BPackageEntry BPackageEntryV1;
typedef BPackageKit::BHPKG::V1::BPackageEntryAttribute BPackageEntryAttributeV1;
typedef BPackageKit::BHPKG::V1::BPrivate::PackageReaderImpl PackageReaderImplV1;
const char* const kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
@@ -95,7 +113,8 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
PackageNode* node;
if (S_ISREG(mode)) {
// file
node = new(std::nothrow) PackageFile(fPackage, mode, entry->Data());
node = new(std::nothrow) PackageFile(fPackage, mode,
PackageData(entry->Data()));
} else if (S_ISLNK(mode)) {
// symlink
String path;
@@ -153,7 +172,8 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
RETURN_ERROR(B_NO_MEMORY);
PackageNodeAttribute* nodeAttribute = new(std::nothrow)
PackageNodeAttribute(attribute->Type(), attribute->Data());
PackageNodeAttribute(attribute->Type(),
PackageData(attribute->Data()));
if (nodeAttribute == NULL)
RETURN_ERROR(B_NO_MEMORY)
@@ -309,6 +329,258 @@ private:
};
// #pragma mark - LoaderContentHandlerV1
struct Package::LoaderContentHandlerV1 : BPackageContentHandlerV1 {
LoaderContentHandlerV1(Package* package)
:
fPackage(package),
fErrorOccurred(false)
{
}
status_t Init()
{
return B_OK;
}
virtual status_t HandleEntry(BPackageEntryV1* entry)
{
if (fErrorOccurred)
return B_OK;
PackageDirectory* parentDir = NULL;
if (entry->Parent() != NULL) {
parentDir = dynamic_cast<PackageDirectory*>(
(PackageNode*)entry->Parent()->UserToken());
if (parentDir == NULL)
RETURN_ERROR(B_BAD_DATA);
}
// get the file mode -- filter out write permissions
mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH);
// create the package node
PackageNode* node;
if (S_ISREG(mode)) {
// file
node = new(std::nothrow) PackageFile(fPackage, mode,
PackageData(entry->Data()));
} else if (S_ISLNK(mode)) {
// symlink
String path;
if (!path.SetTo(entry->SymlinkPath()))
RETURN_ERROR(B_NO_MEMORY);
PackageSymlink* symlink = new(std::nothrow) PackageSymlink(
fPackage, mode);
if (symlink == NULL)
RETURN_ERROR(B_NO_MEMORY);
symlink->SetSymlinkPath(path);
node = symlink;
} else if (S_ISDIR(mode)) {
// directory
node = new(std::nothrow) PackageDirectory(fPackage, mode);
} else
RETURN_ERROR(B_BAD_DATA);
if (node == NULL)
RETURN_ERROR(B_NO_MEMORY);
BReference<PackageNode> nodeReference(node, true);
String entryName;
if (!entryName.SetTo(entry->Name()))
RETURN_ERROR(B_NO_MEMORY);
status_t error = node->Init(parentDir, entryName);
if (error != B_OK)
RETURN_ERROR(error);
node->SetModifiedTime(entry->ModifiedTime());
// add it to the parent directory
if (parentDir != NULL)
parentDir->AddChild(node);
else
fPackage->AddNode(node);
entry->SetUserToken(node);
return B_OK;
}
virtual status_t HandleEntryAttribute(BPackageEntryV1* entry,
BPackageEntryAttributeV1* attribute)
{
if (fErrorOccurred)
return B_OK;
PackageNode* node = (PackageNode*)entry->UserToken();
String name;
if (!name.SetTo(attribute->Name()))
RETURN_ERROR(B_NO_MEMORY);
PackageNodeAttribute* nodeAttribute = new(std::nothrow)
PackageNodeAttribute(attribute->Type(),
PackageData(attribute->Data()));
if (nodeAttribute == NULL)
RETURN_ERROR(B_NO_MEMORY)
nodeAttribute->Init(name);
node->AddAttribute(nodeAttribute);
return B_OK;
}
virtual status_t HandleEntryDone(BPackageEntryV1* entry)
{
return B_OK;
}
virtual status_t HandlePackageAttribute(
const BPackageInfoAttributeValue& value)
{
switch (value.attributeID) {
case B_PACKAGE_INFO_NAME:
{
String name;
if (!name.SetTo(value.string))
return B_NO_MEMORY;
fPackage->SetName(name);
return B_OK;
}
case B_PACKAGE_INFO_INSTALL_PATH:
{
String path;
if (!path.SetTo(value.string))
return B_NO_MEMORY;
fPackage->SetInstallPath(path);
return B_OK;
}
case B_PACKAGE_INFO_VERSION:
{
::Version* version;
status_t error = Version::Create(value.version.major,
value.version.minor, value.version.micro,
value.version.preRelease, value.version.revision, version);
if (error != B_OK)
RETURN_ERROR(error);
fPackage->SetVersion(version);
break;
}
case B_PACKAGE_INFO_ARCHITECTURE:
if (value.unsignedInt >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT)
RETURN_ERROR(B_BAD_VALUE);
fPackage->SetArchitecture(
(BPackageArchitecture)value.unsignedInt);
break;
case B_PACKAGE_INFO_PROVIDES:
{
// create a version object, if a version is specified
::Version* version = NULL;
if (value.resolvable.haveVersion) {
const BPackageVersionData& versionInfo
= value.resolvable.version;
status_t error = Version::Create(versionInfo.major,
versionInfo.minor, versionInfo.micro,
versionInfo.preRelease, versionInfo.revision, version);
if (error != B_OK)
RETURN_ERROR(error);
}
ObjectDeleter< ::Version> versionDeleter(version);
// create a version object, if a compatible version is specified
::Version* compatibleVersion = NULL;
if (value.resolvable.haveCompatibleVersion) {
const BPackageVersionData& versionInfo
= value.resolvable.compatibleVersion;
status_t error = Version::Create(versionInfo.major,
versionInfo.minor, versionInfo.micro,
versionInfo.preRelease, versionInfo.revision,
compatibleVersion);
if (error != B_OK)
RETURN_ERROR(error);
}
ObjectDeleter< ::Version> compatibleVersionDeleter(
compatibleVersion);
// create the resolvable
Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage);
if (resolvable == NULL)
RETURN_ERROR(B_NO_MEMORY);
ObjectDeleter<Resolvable> resolvableDeleter(resolvable);
status_t error = resolvable->Init(value.resolvable.name,
versionDeleter.Detach(), compatibleVersionDeleter.Detach());
if (error != B_OK)
RETURN_ERROR(error);
fPackage->AddResolvable(resolvableDeleter.Detach());
break;
}
case B_PACKAGE_INFO_REQUIRES:
{
// create the dependency
Dependency* dependency = new(std::nothrow) Dependency(fPackage);
if (dependency == NULL)
RETURN_ERROR(B_NO_MEMORY);
ObjectDeleter<Dependency> dependencyDeleter(dependency);
status_t error = dependency->Init(
value.resolvableExpression.name);
if (error != B_OK)
RETURN_ERROR(error);
// create a version object, if a version is specified
::Version* version = NULL;
if (value.resolvableExpression.haveOpAndVersion) {
const BPackageVersionData& versionInfo
= value.resolvableExpression.version;
status_t error = Version::Create(versionInfo.major,
versionInfo.minor, versionInfo.micro,
versionInfo.preRelease, versionInfo.revision, version);
if (error != B_OK)
RETURN_ERROR(error);
dependency->SetVersionRequirement(
value.resolvableExpression.op, version);
}
fPackage->AddDependency(dependencyDeleter.Detach());
break;
}
default:
break;
}
return B_OK;
}
virtual void HandleErrorOccurred()
{
fErrorOccurred = true;
}
private:
Package* fPackage;
bool fErrorOccurred;
};
// #pragma mark - Package
@@ -368,22 +640,38 @@ Package::Load()
// initialize package reader
LoaderErrorOutput errorOutput(this);
PackageReaderImpl packageReader(&errorOutput);
// try current package file format version
{
PackageReaderImpl packageReader(&errorOutput);
status_t error = packageReader.Init(fd, false);
if (error == B_OK) {
// parse content
LoaderContentHandler handler(this);
error = handler.Init();
if (error != B_OK)
RETURN_ERROR(error);
RETURN_ERROR(packageReader.ParseContent(&handler));
}
if (error != B_MISMATCHED_VALUES)
RETURN_ERROR(error);
}
// try package file format version 1
PackageReaderImplV1 packageReader(&errorOutput);
status_t error = packageReader.Init(fd, false);
if (error != B_OK)
RETURN_ERROR(error);
// parse content
LoaderContentHandler handler(this);
LoaderContentHandlerV1 handler(this);
error = handler.Init();
if (error != B_OK)
RETURN_ERROR(error);
error = packageReader.ParseContent(&handler);
if (error != B_OK)
RETURN_ERROR(error);
return B_OK;
RETURN_ERROR(packageReader.ParseContent(&handler));
}
@@ -91,6 +91,7 @@ public:
private:
struct LoaderErrorOutput;
struct LoaderContentHandler;
struct LoaderContentHandlerV1;
private:
mutex fLock;
@@ -0,0 +1,117 @@
/*
* Copyright 2013, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_DATA_H
#define PACKAGE_DATA_H
#include <package/hpkg/PackageData.h>
#include <package/hpkg/v1/PackageData.h>
#include <string.h>
typedef BPackageKit::BHPKG::BPackageData PackageDataV2;
typedef BPackageKit::BHPKG::V1::BPackageData PackageDataV1;
class PackageData {
public:
explicit PackageData(const PackageDataV1& data);
explicit PackageData(const PackageDataV2& data);
uint8 Version() const { return fVersion; }
const PackageDataV1& DataV1() const;
const PackageDataV2& DataV2() const;
uint64 CompressedSize() const;
uint64 UncompressedSize() const;
bool IsEncodedInline() const;
const uint8* InlineData() const;
private:
static const size_t kDataSize = sizeof(PackageDataV1)
> sizeof(PackageDataV2)
? sizeof(PackageDataV1)
: sizeof(PackageDataV2);
private:
union {
char fData[kDataSize];
uint64 fAlignmentDummy;
};
uint8 fVersion;
};
inline
PackageData::PackageData(const PackageDataV1& data)
:
fVersion(1)
{
memcpy(&fData, &data, sizeof(data));
}
inline
PackageData::PackageData(const PackageDataV2& data)
:
fVersion(1)
{
memcpy(&fData, &data, sizeof(data));
}
inline const PackageDataV1&
PackageData::DataV1() const
{
return *(PackageDataV1*)&fData;
}
inline const PackageDataV2&
PackageData::DataV2() const
{
return *(PackageDataV2*)&fData;
}
inline uint64
PackageData::CompressedSize() const
{
if (fVersion == 1)
return DataV1().CompressedSize();
return DataV2().CompressedSize();
}
inline uint64
PackageData::UncompressedSize() const
{
if (fVersion == 1)
return DataV1().UncompressedSize();
return DataV2().UncompressedSize();
}
inline bool
PackageData::IsEncodedInline() const
{
if (fVersion == 1)
return DataV1().IsEncodedInline();
return DataV2().IsEncodedInline();
}
inline const uint8*
PackageData::InlineData() const
{
if (fVersion == 1)
return DataV1().InlineData();
return DataV2().InlineData();
}
#endif // PACKAGE_DATA_H
@@ -48,7 +48,7 @@ private:
struct PackageFile::DataAccessor {
DataAccessor(BPackageData* data)
DataAccessor(PackageData* data)
:
fData(data),
fDataReader(NULL),
@@ -128,7 +128,7 @@ struct PackageFile::DataAccessor {
private:
mutex fLock;
BPackageData* fData;
PackageData* fData;
BDataReader* fDataReader;
BAbstractBufferedDataReader* fReader;
void* fFileCache;
@@ -138,7 +138,7 @@ private:
// #pragma mark - PackageFile
PackageFile::PackageFile(Package* package, mode_t mode, const BPackageData& data)
PackageFile::PackageFile(Package* package, mode_t mode, const PackageData& data)
:
PackageLeafNode(package, mode),
fData(data),
@@ -6,18 +6,14 @@
#define PACKAGE_FILE_H
#include <package/hpkg/PackageData.h>
#include "PackageData.h"
#include "PackageLeafNode.h"
using BPackageKit::BHPKG::BPackageData;
class PackageFile : public PackageLeafNode {
public:
PackageFile(Package* package, mode_t mode,
const BPackageData& data);
const PackageData& data);
virtual ~PackageFile();
virtual status_t VFSInit(dev_t deviceID, ino_t nodeID);
@@ -34,7 +30,7 @@ private:
struct DataAccessor;
private:
BPackageData fData;
PackageData fData;
DataAccessor* fDataAccessor;
};
@@ -11,7 +11,7 @@
PackageNodeAttribute::PackageNodeAttribute(uint32 type,
const BPackageData& data)
const PackageData& data)
:
fData(data),
fName(),
@@ -8,13 +8,11 @@
#include <util/DoublyLinkedList.h>
#include <package/hpkg/PackageData.h>
#include "PackageData.h"
#include "String.h"
using BPackageKit::BHPKG::BPackageData;
class PackageNode;
@@ -22,12 +20,12 @@ class PackageNodeAttribute
: public DoublyLinkedListLinkImpl<PackageNodeAttribute> {
public:
PackageNodeAttribute(uint32 type,
const BPackageData& data);
const PackageData& data);
~PackageNodeAttribute();
const String& Name() const { return fName; }
uint32 Type() const { return fType; }
const BPackageData& Data() const { return fData; }
const PackageData& Data() const { return fData; }
void Init(const String& name);
@@ -37,7 +35,7 @@ public:
{ return fIndexCookie; }
protected:
BPackageData fData;
PackageData fData;
String fName;
void* fIndexCookie;
uint32 fType;