packagefs: Move the package loading code to Package

* Volume::_LoadPackage() -> Package::Load()
* Volume::_DomainEntryCreated(): Pull a bit of code into a new
  _LoadPackage() method for reuse.
This commit is contained in:
Ingo Weinhold 2013-04-07 11:45:47 +02:00
parent 27197fd74b
commit e85e9dadda
4 changed files with 345 additions and 321 deletions

View File

@ -12,13 +12,26 @@
#include <string.h>
#include <unistd.h>
#include <AutoDeleter.h>
#include <package/hpkg/ErrorOutput.h>
#include <package/hpkg/PackageEntry.h>
#include <package/hpkg/PackageEntryAttribute.h>
#include <package/hpkg/PackageReaderImpl.h>
#include <util/AutoLock.h>
#include "DebugSupport.h"
#include "PackageDirectory.h"
#include "PackageDomain.h"
#include "PackageFile.h"
#include "PackageSymlink.h"
#include "Version.h"
using namespace BPackageKit;
using namespace BPackageKit::BHPKG;
using BPackageKit::BHPKG::BPrivate::PackageReaderImpl;
const char* const kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
"any",
"x86",
@ -26,6 +39,267 @@ const char* const kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
};
// #pragma mark - LoaderErrorOutput
struct Package::LoaderErrorOutput : BErrorOutput {
LoaderErrorOutput(Package* package)
:
fPackage(package)
{
}
virtual void PrintErrorVarArgs(const char* format, va_list args)
{
// TODO:...
}
private:
Package* fPackage;
};
// #pragma mark - LoaderContentHandler
struct Package::LoaderContentHandler : BPackageContentHandler {
LoaderContentHandler(Package* package)
:
fPackage(package),
fErrorOccurred(false)
{
}
status_t Init()
{
return B_OK;
}
virtual status_t HandleEntry(BPackageEntry* 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);
}
status_t error;
// 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, entry->Data());
} else if (S_ISLNK(mode)) {
// symlink
PackageSymlink* symlink = new(std::nothrow) PackageSymlink(
fPackage, mode);
if (symlink == NULL)
RETURN_ERROR(B_NO_MEMORY);
error = symlink->SetSymlinkPath(entry->SymlinkPath());
if (error != B_OK) {
delete symlink;
return error;
}
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);
error = node->Init(parentDir, entry->Name());
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(BPackageEntry* entry,
BPackageEntryAttribute* attribute)
{
if (fErrorOccurred)
return B_OK;
PackageNode* node = (PackageNode*)entry->UserToken();
PackageNodeAttribute* nodeAttribute = new(std::nothrow)
PackageNodeAttribute(attribute->Type(), attribute->Data());
if (nodeAttribute == NULL)
RETURN_ERROR(B_NO_MEMORY)
status_t error = nodeAttribute->Init(attribute->Name());
if (error != B_OK) {
delete nodeAttribute;
RETURN_ERROR(error);
}
node->AddAttribute(nodeAttribute);
return B_OK;
}
virtual status_t HandleEntryDone(BPackageEntry* entry)
{
return B_OK;
}
virtual status_t HandlePackageAttribute(
const BPackageInfoAttributeValue& value)
{
switch (value.attributeID) {
case B_PACKAGE_INFO_NAME:
return fPackage->SetName(value.string);
case B_PACKAGE_INFO_INSTALL_PATH:
return fPackage->SetInstallPath(value.string);
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.release, 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.release, 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.release,
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.release, 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
Package::Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID)
:
fDomain(domain),
@ -75,6 +349,36 @@ Package::Init(const char* fileName)
}
status_t
Package::Load()
{
// open package file
int fd = Open();
if (fd < 0)
RETURN_ERROR(fd);
PackageCloser packageCloser(this);
// initialize package reader
LoaderErrorOutput errorOutput(this);
PackageReaderImpl packageReader(&errorOutput);
status_t error = packageReader.Init(fd, false);
if (error != B_OK)
RETURN_ERROR(error);
// parse content
LoaderContentHandler 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;
}
status_t
Package::SetName(const char* name)
{

View File

@ -37,6 +37,7 @@ public:
~Package();
status_t Init(const char* fileName);
status_t Load();
PackageDomain* Domain() const { return fDomain; }
const char* FileName() const { return fFileName; }
@ -86,6 +87,10 @@ public:
const DependencyList& Dependencies() const
{ return fDependencies; }
private:
struct LoaderErrorOutput;
struct LoaderContentHandler;
private:
mutex fLock;
PackageDomain* fDomain;

View File

@ -25,23 +25,15 @@
#include <Notifications.h>
#include <vfs.h>
#include <package/hpkg/ErrorOutput.h>
#include <package/hpkg/PackageEntry.h>
#include <package/hpkg/PackageEntryAttribute.h>
#include <package/hpkg/PackageReaderImpl.h>
#include "AttributeIndex.h"
#include "DebugSupport.h"
#include "kernel_interface.h"
#include "LastModifiedIndex.h"
#include "NameIndex.h"
#include "OldUnpackingNodeAttributes.h"
#include "PackageDirectory.h"
#include "PackageFile.h"
#include "PackageFSRoot.h"
#include "PackageLinkDirectory.h"
#include "PackageLinksDirectory.h"
#include "PackageSymlink.h"
#include "Resolvable.h"
#include "SizeIndex.h"
#include "UnpackingLeafNode.h"
@ -50,11 +42,6 @@
#include "Version.h"
using namespace BPackageKit;
using namespace BPackageKit::BHPKG;
using BPackageKit::BHPKG::BPrivate::PackageReaderImpl;
// node ID of the root directory
static const ino_t kRootDirectoryID = 1;
@ -156,264 +143,6 @@ private:
};
// #pragma mark - PackageLoaderErrorOutput
struct Volume::PackageLoaderErrorOutput : BErrorOutput {
PackageLoaderErrorOutput(Package* package)
:
fPackage(package)
{
}
virtual void PrintErrorVarArgs(const char* format, va_list args)
{
// TODO:...
}
private:
Package* fPackage;
};
// #pragma mark - PackageLoaderContentHandler
struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
PackageLoaderContentHandler(Package* package)
:
fPackage(package),
fErrorOccurred(false)
{
}
status_t Init()
{
return B_OK;
}
virtual status_t HandleEntry(BPackageEntry* 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);
}
status_t error;
// 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, entry->Data());
} else if (S_ISLNK(mode)) {
// symlink
PackageSymlink* symlink = new(std::nothrow) PackageSymlink(
fPackage, mode);
if (symlink == NULL)
RETURN_ERROR(B_NO_MEMORY);
error = symlink->SetSymlinkPath(entry->SymlinkPath());
if (error != B_OK) {
delete symlink;
return error;
}
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);
error = node->Init(parentDir, entry->Name());
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(BPackageEntry* entry,
BPackageEntryAttribute* attribute)
{
if (fErrorOccurred)
return B_OK;
PackageNode* node = (PackageNode*)entry->UserToken();
PackageNodeAttribute* nodeAttribute = new(std::nothrow)
PackageNodeAttribute(attribute->Type(), attribute->Data());
if (nodeAttribute == NULL)
RETURN_ERROR(B_NO_MEMORY)
status_t error = nodeAttribute->Init(attribute->Name());
if (error != B_OK) {
delete nodeAttribute;
RETURN_ERROR(error);
}
node->AddAttribute(nodeAttribute);
return B_OK;
}
virtual status_t HandleEntryDone(BPackageEntry* entry)
{
return B_OK;
}
virtual status_t HandlePackageAttribute(
const BPackageInfoAttributeValue& value)
{
switch (value.attributeID) {
case B_PACKAGE_INFO_NAME:
return fPackage->SetName(value.string);
case B_PACKAGE_INFO_INSTALL_PATH:
return fPackage->SetInstallPath(value.string);
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.release, 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.release, 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.release,
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.release, 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 - DomainDirectoryListener
@ -1039,36 +768,6 @@ Volume::_RemovePackageDomain(PackageDomain* domain)
}
status_t
Volume::_LoadPackage(Package* package)
{
// open package file
int fd = package->Open();
if (fd < 0)
RETURN_ERROR(fd);
PackageCloser packageCloser(package);
// initialize package reader
PackageLoaderErrorOutput errorOutput(package);
PackageReaderImpl packageReader(&errorOutput);
status_t error = packageReader.Init(fd, false);
if (error != B_OK)
RETURN_ERROR(error);
// parse content
PackageLoaderContentHandler handler(package);
error = handler.Init();
if (error != B_OK)
RETURN_ERROR(error);
error = packageReader.ParseContent(&handler);
if (error != B_OK)
RETURN_ERROR(error);
return B_OK;
}
status_t
Volume::_AddPackageContent(Package* package, bool notify)
{
@ -1613,34 +1312,18 @@ Volume::_DomainEntryCreated(PackageDomain* domain, dev_t deviceID,
return;
}
// check whether the entry is a file
struct stat st;
if (fstatat(domain->DirectoryFD(), name, &st, 0) < 0
|| !S_ISREG(st.st_mode)) {
return;
}
// create a package
Package* package = new(std::nothrow) Package(domain, st.st_dev, st.st_ino);
if (package == NULL)
Package* package;
if (_LoadPackage(domain, name, package) != B_OK)
return;
BReference<Package> packageReference(package, true);
status_t error = package->Init(name);
if (error != B_OK)
return;
error = _LoadPackage(package);
if (error != B_OK)
return;
VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
VolumeWriteLocker volumeLocker(this);
domain->AddPackage(package);
// add the package to the node tree
if (addContent) {
error = _AddPackageContent(package, notify);
status_t error = _AddPackageContent(package, notify);
if (error != B_OK) {
domain->RemovePackage(package);
return;
@ -1682,6 +1365,36 @@ Volume::_DomainEntryMoved(PackageDomain* domain, dev_t deviceID,
}
/*static*/ status_t
Volume::_LoadPackage(PackageDomain* domain, const char* name,
Package*& _package)
{
// check whether the entry is a file
struct stat st;
if (fstatat(domain->DirectoryFD(), name, &st, 0) < 0
|| !S_ISREG(st.st_mode)) {
return B_BAD_VALUE;
}
// create a package
Package* package = new(std::nothrow) Package(domain, st.st_dev, st.st_ino);
if (package == NULL)
RETURN_ERROR(B_NO_MEMORY);
BReference<Package> packageReference(package, true);
status_t error = package->Init(name);
if (error != B_OK)
return error;
error = package->Load();
if (error != B_OK)
return error;
_package = packageReference.Detach();
return B_OK;
}
status_t
Volume::_InitMountType(const char* mountType)
{

View File

@ -132,7 +132,6 @@ private:
status_t _AddPackageDomain(PackageDomain* domain,
bool notify);
void _RemovePackageDomain(PackageDomain* domain);
status_t _LoadPackage(Package* package);
status_t _AddPackageContent(Package* package,
bool notify);
@ -177,6 +176,9 @@ private:
ino_t nodeID, const char* fromName,
const char* name, bool notify);
static status_t _LoadPackage(PackageDomain* domain,
const char* name, Package*& _package);
status_t _InitMountType(const char* mountType);
status_t _CreateShineThroughDirectory(Directory* parent,
const char* name, Directory*& _directory);