/*
* Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
* Distributed under the terms of the MIT License.
*/
#include <package/hpkg/RepositoryReaderImpl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <algorithm>
#include <new>
#include <ByteOrder.h>
#include <Message.h>
#include <FdIO.h>
#include <package/hpkg/HPKGDefsPrivate.h>
#include <package/hpkg/RepositoryContentHandler.h>
namespace BPackageKit {
namespace BHPKG {
namespace BPrivate {
//#define TRACE(format...) printf(format)
#define TRACE(format...) do {} while (false)
// maximum repository info size we support reading
static const size_t kMaxRepositoryInfoSize = 1 * 1024 * 1024;
// maximum package attributes size we support reading
static const size_t kMaxPackageAttributesSize = 64 * 1024 * 1024;
// #pragma mark - PackagesAttributeHandler
class RepositoryReaderImpl::PackagesAttributeHandler
: public AttributeHandler {
private:
typedef AttributeHandler super;
public:
PackagesAttributeHandler(BRepositoryContentHandler* contentHandler)
:
fContentHandler(contentHandler),
fPackageName(NULL)
{
}
virtual status_t HandleAttribute(AttributeHandlerContext* context, uint8 id,
const AttributeValue& value, AttributeHandler** _handler)
{
switch (id) {
case B_HPKG_ATTRIBUTE_ID_PACKAGE:
{
status_t error = _NotifyPackageDone();
if (error != B_OK)
return error;
if (_handler != NULL) {
if (fContentHandler != NULL) {
error = fContentHandler->HandlePackage(value.string);
if (error != B_OK)
return error;
}
*_handler = new(std::nothrow) PackageAttributeHandler;
if (*_handler == NULL)
return B_NO_MEMORY;
fPackageName = value.string;
}
break;
}
default:
if (context->ignoreUnknownAttributes)
break;
context->errorOutput->PrintError(
"Error: Invalid package attribute section: unexpected "
"top level attribute id %d encountered\n", id);
return B_BAD_DATA;
}
return B_OK;
}
virtual status_t NotifyDone(AttributeHandlerContext* context)
{
status_t result = _NotifyPackageDone();
if (result == B_OK)
result = super::NotifyDone(context);
return result;
}
private:
status_t _NotifyPackageDone()
{
if (fPackageName == NULL || fContentHandler == NULL)
return B_OK;
status_t error = fContentHandler->HandlePackageDone(fPackageName);
fPackageName = NULL;
return error;
}
private:
BRepositoryContentHandler* fContentHandler;
const char* fPackageName;
};
// #pragma mark - PackageContentHandlerAdapter
class RepositoryReaderImpl::PackageContentHandlerAdapter
: public BPackageContentHandler {
public:
PackageContentHandlerAdapter(BRepositoryContentHandler* contentHandler)
:
fContentHandler(contentHandler)
{
}
virtual status_t HandleEntry(BPackageEntry* entry)
{
return B_OK;
}
virtual status_t HandleEntryAttribute(BPackageEntry* entry,
BPackageEntryAttribute* attribute)
{
return B_OK;
}
virtual status_t HandleEntryDone(BPackageEntry* entry)
{
return B_OK;
}
virtual status_t HandlePackageAttribute(
const BPackageInfoAttributeValue& value)
{
return fContentHandler->HandlePackageAttribute(value);
}
virtual void HandleErrorOccurred()
{
return fContentHandler->HandleErrorOccurred();
}
private:
BRepositoryContentHandler* fContentHandler;
};
// #pragma mark - RepositoryReaderImpl
RepositoryReaderImpl::RepositoryReaderImpl(BErrorOutput* errorOutput)
:
inherited("repository", errorOutput)
{
}
RepositoryReaderImpl::~RepositoryReaderImpl()
{
}
status_t
RepositoryReaderImpl::Init(const char* fileName)
{
// open file
int fd = open(fileName, O_RDONLY);
if (fd < 0) {
ErrorOutput()->PrintError(
"Error: Failed to open repository file \"%s\": %s\n", fileName,
strerror(errno));
return errno;
}
return Init(fd, true);
}
status_t
RepositoryReaderImpl::Init(int fd, bool keepFD)
{
BFdIO* file = new(std::nothrow) BFdIO(fd, keepFD);
if (file == NULL) {
if (keepFD && fd >= 0)
close(fd);
return B_NO_MEMORY;
}
return Init(file, true);
}
status_t
RepositoryReaderImpl::Init(BPositionIO* file, bool keepFile)
{
hpkg_repo_header header;
status_t error = inherited::Init<hpkg_repo_header, B_HPKG_REPO_MAGIC,
B_HPKG_REPO_VERSION, B_HPKG_REPO_MINOR_VERSION>(file, keepFile, header,
0);
if (error != B_OK)
return error;
// init package attributes section
error = InitSection(fPackageAttributesSection,
UncompressedHeapSize(),
B_BENDIAN_TO_HOST_INT64(header.packages_length),
kMaxPackageAttributesSize,
B_BENDIAN_TO_HOST_INT64(header.packages_strings_length),
B_BENDIAN_TO_HOST_INT64(header.packages_strings_count));
if (error != B_OK)
return error;
// init repository info section
PackageFileSection repositoryInfoSection("repository info");
error = InitSection(repositoryInfoSection,
fPackageAttributesSection.offset,
B_BENDIAN_TO_HOST_INT32(header.info_length), kMaxRepositoryInfoSize, 0,
0);
if (error != B_OK)
return error;
// prepare the sections for use
error = PrepareSection(repositoryInfoSection);
if (error != B_OK)
return error;
error = PrepareSection(fPackageAttributesSection);
if (error != B_OK)
return error;
// unarchive repository info
BMessage repositoryInfoArchive;
error = repositoryInfoArchive.Unflatten((char*)repositoryInfoSection.data);
if (error != B_OK) {
ErrorOutput()->PrintError(
"Error: Unable to unflatten repository info archive!\n");
return error;
}
error = fRepositoryInfo.SetTo(&repositoryInfoArchive);
if (error != B_OK) {
ErrorOutput()->PrintError(
"Error: Unable to unarchive repository info!\n");
return error;
}
return B_OK;
}
status_t
RepositoryReaderImpl::GetRepositoryInfo(BRepositoryInfo* _repositoryInfo) const
{
if (_repositoryInfo == NULL)
return B_BAD_VALUE;
*_repositoryInfo = fRepositoryInfo;
return B_OK;
}
status_t
RepositoryReaderImpl::ParseContent(BRepositoryContentHandler* contentHandler)
{
status_t result = contentHandler->HandleRepositoryInfo(fRepositoryInfo);
if (result == B_OK) {
PackageContentHandlerAdapter contentHandlerAdapter(contentHandler);
AttributeHandlerContext context(ErrorOutput(),
contentHandler != NULL ? &contentHandlerAdapter : NULL,
B_HPKG_SECTION_PACKAGE_ATTRIBUTES,
MinorFormatVersion() > B_HPKG_REPO_MINOR_VERSION);
PackagesAttributeHandler rootAttributeHandler(contentHandler);
result = ParsePackageAttributesSection(&context, &rootAttributeHandler);
}
return result;
}
} // namespace BPrivate
} // namespace BHPKG
} // namespace BPackageKit
↑ V595 The 'contentHandler' pointer was utilized before it was verified against nullptr. Check lines: 284, 288.