package list/extract: Add support for hpkg format V1

This commit is contained in:
Ingo Weinhold
2013-05-25 01:12:24 +02:00
parent 11cecf980b
commit 9172ffdb06
2 changed files with 233 additions and 111 deletions
+158 -83
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2009-2011, Ingo Weinhold, [email protected]. * Copyright 2009-2013, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -25,19 +25,68 @@
#include <util/OpenHashTable.h> #include <util/OpenHashTable.h>
#include <package/BlockBufferCacheNoLock.h>
#include <package/hpkg/PackageContentHandler.h> #include <package/hpkg/PackageContentHandler.h>
#include <package/hpkg/PackageDataReader.h> #include <package/hpkg/PackageDataReader.h>
#include <package/hpkg/PackageEntry.h> #include <package/hpkg/PackageEntry.h>
#include <package/hpkg/PackageEntryAttribute.h> #include <package/hpkg/PackageEntryAttribute.h>
#include <package/hpkg/PackageReader.h> #include <package/hpkg/PackageReader.h>
#include <package/hpkg/StandardErrorOutput.h> #include <package/hpkg/StandardErrorOutput.h>
#include <package/BlockBufferCacheNoLock.h> #include <package/hpkg/v1/PackageContentHandler.h>
#include <package/hpkg/v1/PackageDataReader.h>
#include <package/hpkg/v1/PackageEntry.h>
#include <package/hpkg/v1/PackageEntryAttribute.h>
#include <package/hpkg/v1//PackageReader.h>
#include "package.h" #include "package.h"
using namespace BPackageKit::BHPKG;
using BPackageKit::BBlockBufferCacheNoLock; using BPackageKit::BBlockBufferCacheNoLock;
using BPackageKit::BHPKG::BAbstractBufferedDataReader;
using BPackageKit::BHPKG::BBufferDataReader;
using BPackageKit::BHPKG::BDataReader;
using BPackageKit::BHPKG::BFDDataReader;
using BPackageKit::BHPKG::BPackageInfoAttributeValue;
using BPackageKit::BHPKG::BStandardErrorOutput;
struct VersionPolicyV1 {
typedef BPackageKit::BHPKG::V1::BPackageContentHandler
PackageContentHandler;
typedef BPackageKit::BHPKG::V1::BPackageData PackageData;
typedef BPackageKit::BHPKG::V1::BPackageDataReaderFactory
PackageDataReaderFactory;
typedef BPackageKit::BHPKG::V1::BPackageEntry PackageEntry;
typedef BPackageKit::BHPKG::V1::BPackageEntryAttribute
PackageEntryAttribute;
typedef BPackageKit::BHPKG::V1::BPackageReader PackageReader;
static const int kDefaultDataChunkSize
= BPackageKit::BHPKG::V1::B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB;
static inline const char* PackageInfoFileName()
{
return BPackageKit::BHPKG::V1::B_HPKG_PACKAGE_INFO_FILE_NAME;
}
};
struct VersionPolicyV2 {
typedef BPackageKit::BHPKG::BPackageContentHandler PackageContentHandler;
typedef BPackageKit::BHPKG::BPackageData PackageData;
typedef BPackageKit::BHPKG::BPackageDataReaderFactory
PackageDataReaderFactory;
typedef BPackageKit::BHPKG::BPackageEntry PackageEntry;
typedef BPackageKit::BHPKG::BPackageEntryAttribute PackageEntryAttribute;
typedef BPackageKit::BHPKG::BPackageReader PackageReader;
static const int kDefaultDataChunkSize
= BPackageKit::BHPKG::B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB;
static inline const char* PackageInfoFileName()
{
return BPackageKit::BHPKG::B_HPKG_PACKAGE_INFO_FILE_NAME;
}
};
struct Entry { struct Entry {
@@ -176,10 +225,11 @@ private:
}; };
struct PackageContentExtractHandler : BPackageContentHandler { template<typename VersionPolicy>
struct PackageContentExtractHandler : VersionPolicy::PackageContentHandler {
PackageContentExtractHandler(int packageFileFD) PackageContentExtractHandler(int packageFileFD)
: :
fBufferCache(B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB, 2), fBufferCache(VersionPolicy::kDefaultDataChunkSize, 2),
fPackageFileReader(packageFileFD), fPackageFileReader(packageFileFD),
fDataBuffer(NULL), fDataBuffer(NULL),
fDataBufferSize(0), fDataBufferSize(0),
@@ -280,7 +330,7 @@ struct PackageContentExtractHandler : BPackageContentHandler {
return entry; return entry;
} }
virtual status_t HandleEntry(BPackageEntry* entry) virtual status_t HandleEntry(typename VersionPolicy::PackageEntry* entry)
{ {
// create a token // create a token
Token* token = new(std::nothrow) Token; Token* token = new(std::nothrow) Token;
@@ -385,7 +435,7 @@ struct PackageContentExtractHandler : BPackageContentHandler {
// write data // write data
status_t error; status_t error;
const BPackageData& data = entry->Data(); const typename VersionPolicy::PackageData& data = entry->Data();
if (data.IsEncodedInline()) { if (data.IsEncodedInline()) {
BBufferDataReader dataReader(data.InlineData(), BBufferDataReader dataReader(data.InlineData(),
data.CompressedSize()); data.CompressedSize());
@@ -452,8 +502,9 @@ struct PackageContentExtractHandler : BPackageContentHandler {
return B_OK; return B_OK;
} }
virtual status_t HandleEntryAttribute(BPackageEntry* entry, virtual status_t HandleEntryAttribute(
BPackageEntryAttribute* attribute) typename VersionPolicy::PackageEntry* entry,
typename VersionPolicy::PackageEntryAttribute* attribute)
{ {
// don't write attributes of ignored or implicit entries // don't write attributes of ignored or implicit entries
Token* token = (Token*)entry->UserToken(); Token* token = (Token*)entry->UserToken();
@@ -478,7 +529,7 @@ struct PackageContentExtractHandler : BPackageContentHandler {
// write data // write data
status_t error; status_t error;
const BPackageData& data = attribute->Data(); const typename VersionPolicy::PackageData& data = attribute->Data();
if (data.IsEncodedInline()) { if (data.IsEncodedInline()) {
BBufferDataReader dataReader(data.InlineData(), BBufferDataReader dataReader(data.InlineData(),
data.CompressedSize()); data.CompressedSize());
@@ -491,7 +542,8 @@ struct PackageContentExtractHandler : BPackageContentHandler {
return error; return error;
} }
virtual status_t HandleEntryDone(BPackageEntry* entry) virtual status_t HandleEntryDone(
typename VersionPolicy::PackageEntry* entry)
{ {
Token* token = (Token*)entry->UserToken(); Token* token = (Token*)entry->UserToken();
@@ -561,13 +613,13 @@ private:
return Entry::Create(parentEntry, name.String(), implicit, _entry); return Entry::Create(parentEntry, name.String(), implicit, _entry);
} }
void _GetParentFDAndEntryName(BPackageEntry* entry, int& _parentFD, void _GetParentFDAndEntryName(typename VersionPolicy::PackageEntry* entry,
const char*& _entryName) int& _parentFD, const char*& _entryName)
{ {
_entryName = entry->Name(); _entryName = entry->Name();
if (fInfoFileName != NULL if (fInfoFileName != NULL
&& strcmp(_entryName, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) { && strcmp(_entryName, VersionPolicy::PackageInfoFileName()) == 0) {
_parentFD = AT_FDCWD; _parentFD = AT_FDCWD;
_entryName = fInfoFileName; _entryName = fInfoFileName;
} else { } else {
@@ -576,11 +628,12 @@ private:
} }
} }
BString _EntryPath(const BPackageEntry* entry) BString _EntryPath(const typename VersionPolicy::PackageEntry* entry)
{ {
BString path; BString path;
if (const BPackageEntry* parent = entry->Parent()) { if (const typename VersionPolicy::PackageEntry* parent
= entry->Parent()) {
path = _EntryPath(parent); path = _EntryPath(parent);
path << '/'; path << '/';
} }
@@ -589,12 +642,13 @@ private:
return path; return path;
} }
status_t _ExtractFileData(BDataReader* dataReader, const BPackageData& data, status_t _ExtractFileData(BDataReader* dataReader,
int fd) const typename VersionPolicy::PackageData& data, int fd)
{ {
// create a PackageDataReader // create a PackageDataReader
BAbstractBufferedDataReader* reader; BAbstractBufferedDataReader* reader;
status_t error = BPackageDataReaderFactory(&fBufferCache) status_t error = typename VersionPolicy::PackageDataReaderFactory(
&fBufferCache)
.CreatePackageDataReader(dataReader, data, reader); .CreatePackageDataReader(dataReader, data, reader);
if (error != B_OK) if (error != B_OK)
return error; return error;
@@ -645,6 +699,83 @@ private:
}; };
template<typename VersionPolicy>
static void
do_extract(const char* packageFileName, const char* changeToDirectory,
const char* packageInfoFileName, const char* const* explicitEntries,
int explicitEntryCount, bool ignoreVersionError)
{
// open package
BStandardErrorOutput errorOutput;
typename VersionPolicy::PackageReader packageReader(&errorOutput);
status_t error = packageReader.Init(packageFileName);
if (error != B_OK) {
if (ignoreVersionError && error == B_MISMATCHED_VALUES)
return;
exit(1);
}
PackageContentExtractHandler<VersionPolicy> handler(
packageReader.PackageFileFD());
error = handler.Init();
if (error != B_OK)
exit(1);
// If entries to extract have been specified explicitly, add those to the
// filtered ones.
if (explicitEntryCount > 0) {
for (int i = 0; i < explicitEntryCount; i++) {
const char* entryName = explicitEntries[i];
if (entryName[0] == '\0' || entryName[0] == '/') {
fprintf(stderr, "Error: Invalid entry name: \"%s\".",
entryName);
exit(1);
}
if (handler.AddFilterEntry(entryName) != B_OK)
exit(1);
}
} else
handler.SetExtractAll();
// get the target directory, if requested
if (changeToDirectory != NULL) {
int currentDirFD = open(changeToDirectory, O_RDONLY);
if (currentDirFD < 0) {
fprintf(stderr, "Error: Failed to change the current working "
"directory to \"%s\": %s\n", changeToDirectory,
strerror(errno));
exit(1);
}
handler.SetBaseDirectory(currentDirFD);
}
// If a package info file name is given, set it.
if (packageInfoFileName != NULL)
handler.SetPackageInfoFile(packageInfoFileName);
// extract
error = packageReader.ParseContent(&handler);
if (error != B_OK)
exit(1);
// check whether all explicitly specified entries have been extracted
if (explicitEntryCount > 0) {
for (int i = 0; i < explicitEntryCount; i++) {
if (Entry* entry = handler.FindFilterEntry(explicitEntries[i])) {
if (!entry->Seen()) {
fprintf(stderr, "Warning: Entry \"%s\" not found.\n",
explicitEntries[i]);
}
}
}
}
exit(0);
}
int int
command_extract(int argc, const char* const* argv) command_extract(int argc, const char* const* argv)
{ {
@@ -681,75 +812,19 @@ command_extract(int argc, const char* const* argv)
} }
} }
// At least one argument should remain -- the package file name. // At least one argument should remain -- the package file name. Any further
// arguments are the names of the entries to extract.
if (optind + 1 > argc) if (optind + 1 > argc)
print_usage_and_exit(true); print_usage_and_exit(true);
const char* packageFileName = argv[optind++]; const char* packageFileName = argv[optind++];
const char* const* explicitEntries = argv + optind;
int explicitEntryCount = argc - optind;
// open package do_extract<VersionPolicyV2>(packageFileName, changeToDirectory,
BStandardErrorOutput errorOutput; packageInfoFileName, explicitEntries, explicitEntryCount, true);
BPackageReader packageReader(&errorOutput); do_extract<VersionPolicyV1>(packageFileName, changeToDirectory,
status_t error = packageReader.Init(packageFileName); packageInfoFileName, explicitEntries, explicitEntryCount, false);
if (error != B_OK)
return 1;
PackageContentExtractHandler handler(packageReader.PackageFileFD());
error = handler.Init();
if (error != B_OK)
return 1;
// If entries to extract have been specified explicitly, add those to the
// filtered ones.
int explicitEntriesIndex = optind;
if (optind < argc) {
while (optind < argc) {
const char* entryName = argv[optind++];
if (entryName[0] == '\0' || entryName[0] == '/') {
fprintf(stderr, "Error: Invalid entry name: \"%s\".",
entryName);
return 1;
}
if (handler.AddFilterEntry(entryName) != B_OK)
return 1;
}
} else
handler.SetExtractAll();
// get the target directory, if requested
if (changeToDirectory != NULL) {
int currentDirFD = open(changeToDirectory, O_RDONLY);
if (currentDirFD < 0) {
fprintf(stderr, "Error: Failed to change the current working "
"directory to \"%s\": %s\n", changeToDirectory,
strerror(errno));
return 1;
}
handler.SetBaseDirectory(currentDirFD);
}
// If a package info file name is given, set it.
if (packageInfoFileName != NULL)
handler.SetPackageInfoFile(packageInfoFileName);
// extract
error = packageReader.ParseContent(&handler);
if (error != B_OK)
return 1;
// check whether all explicitly specified entries have been extracted
if (explicitEntriesIndex < argc) {
for (int i = explicitEntriesIndex; i < argc; i++) {
if (Entry* entry = handler.FindFilterEntry(argv[i])) {
if (!entry->Seen()) {
fprintf(stderr, "Warning: Entry \"%s\" not found.\n",
argv[i]);
}
}
}
}
return 0; return 0;
} }
+75 -28
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2009-2011, Ingo Weinhold, [email protected]. * Copyright 2009-2013, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -18,17 +18,39 @@
#include <package/hpkg/PackageInfoAttributeValue.h> #include <package/hpkg/PackageInfoAttributeValue.h>
#include <package/hpkg/PackageReader.h> #include <package/hpkg/PackageReader.h>
#include <package/hpkg/StandardErrorOutput.h> #include <package/hpkg/StandardErrorOutput.h>
#include <package/hpkg/v1/PackageContentHandler.h>
#include <package/hpkg/v1/PackageEntry.h>
#include <package/hpkg/v1/PackageEntryAttribute.h>
#include <package/hpkg/v1//PackageReader.h>
#include <package/PackageInfo.h> #include <package/PackageInfo.h>
#include "package.h" #include "package.h"
using namespace BPackageKit::BHPKG;
using namespace BPackageKit; using namespace BPackageKit;
using BPackageKit::BHPKG::BPackageInfoAttributeValue;
struct PackageContentListHandler : BPackageContentHandler { struct VersionPolicyV1 {
typedef BPackageKit::BHPKG::V1::BPackageContentHandler
PackageContentHandler;
typedef BPackageKit::BHPKG::V1::BPackageEntry PackageEntry;
typedef BPackageKit::BHPKG::V1::BPackageEntryAttribute
PackageEntryAttribute;
typedef BPackageKit::BHPKG::V1::BPackageReader PackageReader;
};
struct VersionPolicyV2 {
typedef BPackageKit::BHPKG::BPackageContentHandler PackageContentHandler;
typedef BPackageKit::BHPKG::BPackageEntry PackageEntry;
typedef BPackageKit::BHPKG::BPackageEntryAttribute PackageEntryAttribute;
typedef BPackageKit::BHPKG::BPackageReader PackageReader;
};
template<typename VersionPolicy>
struct PackageContentListHandler : VersionPolicy::PackageContentHandler {
PackageContentListHandler(bool listAttributes) PackageContentListHandler(bool listAttributes)
: :
fLevel(0), fLevel(0),
@@ -36,7 +58,7 @@ struct PackageContentListHandler : BPackageContentHandler {
{ {
} }
virtual status_t HandleEntry(BPackageEntry* entry) virtual status_t HandleEntry(typename VersionPolicy::PackageEntry* entry)
{ {
fLevel++; fLevel++;
@@ -80,8 +102,9 @@ struct PackageContentListHandler : BPackageContentHandler {
return B_OK; return B_OK;
} }
virtual status_t HandleEntryAttribute(BPackageEntry* entry, virtual status_t HandleEntryAttribute(
BPackageEntryAttribute* attribute) typename VersionPolicy::PackageEntry* entry,
typename VersionPolicy::PackageEntryAttribute* attribute)
{ {
if (!fListAttribute) if (!fListAttribute)
return B_OK; return B_OK;
@@ -104,7 +127,8 @@ struct PackageContentListHandler : BPackageContentHandler {
return B_OK; return B_OK;
} }
virtual status_t HandleEntryDone(BPackageEntry* entry) virtual status_t HandleEntryDone(
typename VersionPolicy::PackageEntry* entry)
{ {
fLevel--; fLevel--;
return B_OK; return B_OK;
@@ -274,27 +298,30 @@ private:
}; };
struct PackageContentListPathsHandler : BPackageContentHandler { template<typename VersionPolicy>
struct PackageContentListPathsHandler : VersionPolicy::PackageContentHandler {
PackageContentListPathsHandler() PackageContentListPathsHandler()
: :
fPathComponents() fPathComponents()
{ {
} }
virtual status_t HandleEntry(BPackageEntry* entry) virtual status_t HandleEntry(typename VersionPolicy::PackageEntry* entry)
{ {
fPathComponents.Add(entry->Name()); fPathComponents.Add(entry->Name());
printf("%s\n", fPathComponents.Join("/").String()); printf("%s\n", fPathComponents.Join("/").String());
return B_OK; return B_OK;
} }
virtual status_t HandleEntryAttribute(BPackageEntry* entry, virtual status_t HandleEntryAttribute(
BPackageEntryAttribute* attribute) typename VersionPolicy::PackageEntry* entry,
typename VersionPolicy::PackageEntryAttribute* attribute)
{ {
return B_OK; return B_OK;
} }
virtual status_t HandleEntryDone(BPackageEntry* entry) virtual status_t HandleEntryDone(
typename VersionPolicy::PackageEntry* entry)
{ {
fPathComponents.Remove(fPathComponents.CountStrings() - 1); fPathComponents.Remove(fPathComponents.CountStrings() - 1);
return B_OK; return B_OK;
@@ -315,6 +342,36 @@ private:
}; };
template<typename VersionPolicy>
static void
do_list(const char* packageFileName, bool listAttributes, bool filePathsOnly,
bool ignoreVersionError)
{
// open package
BHPKG::BStandardErrorOutput errorOutput;
typename VersionPolicy::PackageReader packageReader(&errorOutput);
status_t error = packageReader.Init(packageFileName);
if (error != B_OK) {
if (ignoreVersionError && error == B_MISMATCHED_VALUES)
return;
exit(1);
}
// list
if (filePathsOnly) {
PackageContentListPathsHandler<VersionPolicy> handler;
error = packageReader.ParseContent(&handler);
} else {
PackageContentListHandler<VersionPolicy> handler(listAttributes);
error = packageReader.ParseContent(&handler);
}
if (error != B_OK)
exit(1);
exit(0);
}
int int
command_list(int argc, const char* const* argv) command_list(int argc, const char* const* argv)
{ {
@@ -357,23 +414,13 @@ command_list(int argc, const char* const* argv)
const char* packageFileName = argv[optind++]; const char* packageFileName = argv[optind++];
// open package BHPKG::BStandardErrorOutput errorOutput;
BStandardErrorOutput errorOutput;
BPackageReader packageReader(&errorOutput);
status_t error = packageReader.Init(packageFileName);
if (error != B_OK)
return 1;
// list // current package file format version
if (filePathsOnly) { do_list<VersionPolicyV2>(packageFileName, listAttributes, filePathsOnly,
PackageContentListPathsHandler handler; true);
error = packageReader.ParseContent(&handler); do_list<VersionPolicyV1>(packageFileName, listAttributes, filePathsOnly,
} else { false);
PackageContentListHandler handler(listAttributes);
error = packageReader.ParseContent(&handler);
}
if (error != B_OK)
return 1;
return 0; return 0;
} }