Implemented a tool ("package") that implements creation and extraction of

packages of the newly invented Haiku Package format
(http://dev.haiku-os.org/wiki/PackageFormat). It basically works, but it's
still work in progress (e.g. compression is not implemented yet), as is the
format itself.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34018 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-11-13 13:45:49 +00:00
parent 8735f4fde6
commit 050aa61bd6
28 changed files with 4645 additions and 0 deletions

View File

@ -0,0 +1,155 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _HAIKU_PACKAGE_H
#define _HAIKU_PACKAGE_H
#include <SupportDefs.h>
// header
struct hpkg_header {
uint32 magic; // "hpkg"
uint16 header_size;
uint16 version;
uint64 total_size;
// package attributes section
uint32 attributes_compression;
uint32 attributes_length_compressed;
uint32 attributes_length_uncompressed;
// TOC section
uint32 toc_compression;
uint64 toc_length_compressed;
uint64 toc_length_uncompressed;
uint64 toc_attribute_types_length;
uint64 toc_attribute_types_count;
uint64 toc_strings_length;
uint64 toc_strings_count;
};
// magic, version
enum {
B_HPKG_MAGIC = 'hpkg',
B_HPKG_VERSION = 1
};
// compression types
enum {
B_HPKG_COMPRESSION_NONE = 0,
B_HPKG_COMPRESSION_ZLIB = 1
};
// attribute types
enum {
// types
B_HPKG_ATTRIBUTE_TYPE_INVALID = 0,
B_HPKG_ATTRIBUTE_TYPE_INT = 1,
B_HPKG_ATTRIBUTE_TYPE_UINT = 2,
B_HPKG_ATTRIBUTE_TYPE_STRING = 3,
B_HPKG_ATTRIBUTE_TYPE_RAW = 4
};
// attribute encodings
enum {
// signed/unsigned int encodings
B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT = 0,
B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT = 1,
B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT = 2,
B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT = 3,
// string encodings
B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE = 0,
// null-terminated string
B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE = 1,
// unsigned LEB128 index into string table
// raw data encodings
B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE = 0,
// unsigned LEB128 size, raw bytes
B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP = 1
// unsigned LEB128 size, unsigned LEB128 offset into the heap
};
// attribute tag arithmetics
#define B_HPKG_ATTRIBUTE_TAG_COMPOSE(index, encoding, hasChildren) \
(((uint64(index) << 3) | uint64(encoding) << 1 \
| ((hasChildren) ? 1 : 0)) + 1)
#define B_HPKG_ATTRIBUTE_TAG_INDEX(tag) (uint64((tag) - 1) >> 3)
#define B_HPKG_ATTRIBUTE_TAG_ENCODING(tag) ((uint64((tag) - 1) >> 1) & 0x3)
#define B_HPKG_ATTRIBUTE_TAG_HAS_CHILDREN(tag) ((uint64((tag) - 1) & 0x1) != 0)
// standard attribute names
#define B_HPKG_ATTRIBUTE_NAME_DIRECTORY_ENTRY "dir:entry"
// path/entry name (string)
#define B_HPKG_ATTRIBUTE_NAME_FILE_TYPE "file:type"
// file type (uint)
#define B_HPKG_ATTRIBUTE_NAME_FILE_PERMISSIONS "file:permissions"
// file permissions (uint)
#define B_HPKG_ATTRIBUTE_NAME_FILE_USER "file:user"
// file user (string)
#define B_HPKG_ATTRIBUTE_NAME_FILE_GROUP "file:group"
// file group (string)
#define B_HPKG_ATTRIBUTE_NAME_FILE_ATIME "file:atime"
// file access time in seconds (uint)
#define B_HPKG_ATTRIBUTE_NAME_FILE_MTIME "file:mtime"
// file modification time in seconds (uint)
#define B_HPKG_ATTRIBUTE_NAME_FILE_CRTIME "file:crtime"
// file creation time in seconds (uint)
#define B_HPKG_ATTRIBUTE_NAME_FILE_ATIME_NANOS "file:atime:nanos"
// file access time nanoseconds fraction (uint)
#define B_HPKG_ATTRIBUTE_NAME_FILE_MTIME_NANOS "file:mtime:nanos"
// file modification time nanoseconds fraction (uint)
#define B_HPKG_ATTRIBUTE_NAME_FILE_CRTIM_NANOS "file:crtime:nanos"
// file creation time nanoseconds fraction (uint)
#define B_HPKG_ATTRIBUTE_NAME_FILE_ATTRIBUTE "file:attribute"
// file attribute (string)
#define B_HPKG_ATTRIBUTE_NAME_FILE_ATTRIBUTE_TYPE "file:attribute:type"
// file attribute type (uint)
#define B_HPKG_ATTRIBUTE_NAME_DATA "data"
// (file/attribute) data (raw)
#define B_HPKG_ATTRIBUTE_NAME_DATA_COMPRESSION "data:compression"
// (file/attribute) data compression (uint, default: none)
#define B_HPKG_ATTRIBUTE_NAME_DATA_SIZE "data:size"
// (file/attribute) uncompressed data size (uint)
#define B_HPKG_ATTRIBUTE_NAME_DATA_CHUNK_SIZE "data:chunk_size"
// the size of compressed (file/attribute) data chunks (uint)
#define B_HPKG_ATTRIBUTE_NAME_SYMLINK_PATH "symlink:path"
// symlink path (string)
// file types (B_HPKG_ATTRIBUTE_NAME_FILE_TYPE)
enum {
B_HPKG_FILE_TYPE_FILE = 0,
B_HPKG_FILE_TYPE_DIRECTORY = 1,
B_HPKG_FILE_TYPE_SYMLINK = 2
};
// maximum number of bytes of data to be encoded inline; more will be allocated
// on the heap
#define B_HPKG_MAX_INLINE_DATA_SIZE 8
// default values
enum {
B_HPKG_DEFAULT_FILE_TYPE = B_HPKG_FILE_TYPE_FILE,
B_HPKG_DEFAULT_FILE_PERMISSIONS = 0644,
B_HPKG_DEFAULT_DIRECTORY_PERMISSIONS = 0755,
B_HPKG_DEFAULT_SYMLINK_PERMISSIONS = 0777,
B_HPKG_DEFAULT_DATA_COMPRESSION = B_HPKG_COMPRESSION_NONE,
B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB = 64 * 1024
};
#endif // _HAIKU_PACKAGE_H

View File

@ -218,6 +218,7 @@ SubInclude HAIKU_TOP src bin mkdepend ;
SubInclude HAIKU_TOP src bin mkdos ;
SubInclude HAIKU_TOP src bin mkfs ;
SubInclude HAIKU_TOP src bin multiuser ;
SubInclude HAIKU_TOP src bin package ;
SubInclude HAIKU_TOP src bin patch ;
SubInclude HAIKU_TOP src bin pc ;
SubInclude HAIKU_TOP src bin pcmcia-cs ;

View File

@ -0,0 +1,67 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "DataReader.h"
#include <errno.h>
#include <string.h>
#include <unistd.h>
// #pragma mark - DataReader
DataReader::~DataReader()
{
}
// #pragma mark - FDDataReader
FDDataReader::FDDataReader(int fd)
:
fFD(fd)
{
}
status_t
FDDataReader::ReadData(off_t offset, void* buffer, size_t size)
{
ssize_t bytesRead = pread(fFD, buffer, size, offset);
if (bytesRead < 0)
return errno;
return (size_t)bytesRead == size ? B_OK : B_ERROR;
}
// #pragma mark - BufferDataReader
BufferDataReader::BufferDataReader(const void* data, size_t size)
:
fData(data),
fSize(size)
{
}
status_t
BufferDataReader::ReadData(off_t offset, void* buffer, size_t size)
{
if (size == 0)
return B_OK;
if (offset < 0)
return B_BAD_VALUE;
if (size > fSize || offset > fSize - size)
return B_ERROR;
memcpy(buffer, (const uint8*)fData + offset, size);
return B_OK;
}

View File

@ -0,0 +1,46 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef DATA_READER_H
#define DATA_READER_H
#include <SupportDefs.h>
class DataReader {
public:
virtual ~DataReader();
virtual status_t ReadData(off_t offset, void* buffer,
size_t size) = 0;
};
class FDDataReader : public DataReader {
public:
FDDataReader(int fd);
virtual status_t ReadData(off_t offset, void* buffer,
size_t size);
private:
int fFD;
};
class BufferDataReader : public DataReader {
public:
BufferDataReader(const void* data, size_t size);
virtual status_t ReadData(off_t offset, void* buffer,
size_t size);
private:
const void* fData;
size_t fSize;
};
#endif // DATA_READER_H

View File

@ -0,0 +1,27 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef FD_CLOSER_H
#define FD_CLOSER_H
struct FDCloser {
FDCloser(int fd)
:
fFD(fd)
{
}
~FDCloser()
{
if (fFD >= 0)
close(fFD);
}
private:
int fFD;
};
#endif // FD_CLOSER_H

25
src/bin/package/Jamfile Normal file
View File

@ -0,0 +1,25 @@
SubDir HAIKU_TOP src bin package ;
UsePrivateHeaders kernel shared ;
UsePrivateHeaders haiku_package ;
DEFINES += B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT ;
# TODO: Remove when it is complete!
BinCommand package :
command_create.cpp
command_dump.cpp
command_extract.cpp
command_list.cpp
DataReader.cpp
package.cpp
PackageData.cpp
PackageDataReader.cpp
PackageEntry.cpp
PackageEntryAttribute.cpp
PackageReader.cpp
PackageWriter.cpp
Strings.cpp
:
$(TARGET_LIBSUPC++)
;

View File

@ -0,0 +1,147 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_ATTRIBUTE_VALUE_H
#define PACKAGE_ATTRIBUTE_VALUE_H
#include <string.h>
#include <haiku_package.h>
struct PackageAttributeValue {
union {
int64 signedInt;
uint64 unsignedInt;
const char* string;
struct {
uint64 size;
union {
uint64 offset;
uint8 raw[B_HPKG_MAX_INLINE_DATA_SIZE];
};
} data;
};
uint8 type;
uint8 encoding;
public:
inline PackageAttributeValue();
inline void SetTo(int8 value);
inline void SetTo(uint8 value);
inline void SetTo(int16 value);
inline void SetTo(uint16 value);
inline void SetTo(int32 value);
inline void SetTo(uint32 value);
inline void SetTo(int64 value);
inline void SetTo(uint64 value);
inline void SetTo(const char* value);
inline void SetToData(uint64 size, uint64 offset);
inline void SetToData(uint64 size, const void* rawData);
};
PackageAttributeValue::PackageAttributeValue()
:
type(B_HPKG_ATTRIBUTE_TYPE_INVALID)
{
}
void
PackageAttributeValue::SetTo(int8 value)
{
signedInt = value;
type = B_HPKG_ATTRIBUTE_TYPE_INT;
}
void
PackageAttributeValue::SetTo(uint8 value)
{
unsignedInt = value;
type = B_HPKG_ATTRIBUTE_TYPE_UINT;
}
void
PackageAttributeValue::SetTo(int16 value)
{
signedInt = value;
type = B_HPKG_ATTRIBUTE_TYPE_INT;
}
void
PackageAttributeValue::SetTo(uint16 value)
{
unsignedInt = value;
type = B_HPKG_ATTRIBUTE_TYPE_UINT;
}
void
PackageAttributeValue::SetTo(int32 value)
{
signedInt = value;
type = B_HPKG_ATTRIBUTE_TYPE_INT;
}
void
PackageAttributeValue::SetTo(uint32 value)
{
unsignedInt = value;
type = B_HPKG_ATTRIBUTE_TYPE_UINT;
}
void
PackageAttributeValue::SetTo(int64 value)
{
signedInt = value;
type = B_HPKG_ATTRIBUTE_TYPE_INT;
}
void
PackageAttributeValue::SetTo(uint64 value)
{
unsignedInt = value;
type = B_HPKG_ATTRIBUTE_TYPE_UINT;
}
void
PackageAttributeValue::SetTo(const char* value)
{
string = value;
type = B_HPKG_ATTRIBUTE_TYPE_STRING;
}
void
PackageAttributeValue::SetToData(uint64 size, uint64 offset)
{
data.size = size;
data.offset = offset;
type = B_HPKG_ATTRIBUTE_TYPE_RAW;
encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP;
}
void
PackageAttributeValue::SetToData(uint64 size, const void* rawData)
{
data.size = size;
if (size > 0)
memcpy(data.raw, rawData, size);
type = B_HPKG_ATTRIBUTE_TYPE_RAW;
encoding = B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE;
}
#endif // PACKAGE_ATTRIBUTE_VALUE_H

View File

@ -0,0 +1,38 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "PackageData.h"
#include <string.h>
PackageData::PackageData()
:
fCompressedSize(0),
fUncompressedSize(0),
fCompression(B_HPKG_COMPRESSION_NONE),
fEncodedInline(true)
{
}
void
PackageData::SetData(uint64 size, uint64 offset)
{
fUncompressedSize = fCompressedSize = size;
fOffset = offset;
fEncodedInline = false;
}
void
PackageData::SetData(uint8 size, const void* data)
{
fUncompressedSize = fCompressedSize = size;
if (size > 0)
memcpy(fInlineData, data, size);
fEncodedInline = true;
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_DATA_H
#define PACKAGE_DATA_H
#include <haiku_package.h>
class PackageData {
public:
PackageData();
uint64 CompressedSize() const
{ return fCompressedSize; }
uint64 UncompressedSize() const
{ return fUncompressedSize; }
uint64 Offset() const { return fOffset; }
uint32 Compression() const { return fCompression; }
bool IsEncodedInline() const
{ return fEncodedInline; }
const uint8* InlineData() const { return fInlineData; }
void SetData(uint64 size, uint64 offset);
void SetData(uint8 size, const void* data);
void SetCompression(uint32 compression)
{ fCompression = compression; }
void SetUncompressedSize(uint64 size)
{ fUncompressedSize = size; }
private:
uint64 fCompressedSize;
uint64 fUncompressedSize;
union {
uint64 fOffset;
uint8 fInlineData[B_HPKG_MAX_INLINE_DATA_SIZE];
};
uint32 fCompression;
bool fEncodedInline;
};
#endif // PACKAGE_DATA_H

View File

@ -0,0 +1,112 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "PackageDataReader.h"
#include <new>
#include <haiku_package.h>
#include "PackageData.h"
// #pragma mark - PackageDataReader
PackageDataReader::PackageDataReader(DataReader* dataReader)
:
fDataReader(dataReader)
{
}
PackageDataReader::~PackageDataReader()
{
}
// #pragma mark - UncompressedPackageDataReader
class UncompressedPackageDataReader : public PackageDataReader {
public:
UncompressedPackageDataReader(DataReader* dataReader)
:
PackageDataReader(dataReader)
{
}
status_t Init(const PackageData& data)
{
fOffset = data.Offset();
fSize = data.UncompressedSize();
return B_OK;
}
virtual uint64 Size() const
{
return fSize;
}
virtual size_t BlockSize() const
{
// TODO: Some other value?
return 64 * 1024;
}
virtual status_t ReadData(off_t offset, void* buffer, size_t size)
{
if (size == 0)
return B_OK;
if (offset < 0)
return B_BAD_VALUE;
if ((uint64)offset > fSize || size > fSize - offset)
return B_ERROR;
return fDataReader->ReadData(fOffset + offset, buffer, size);
}
private:
uint64 fOffset;
uint64 fSize;
};
// #pragma mark - PackageDataReaderFactory
/*static*/ status_t
PackageDataReaderFactory::CreatePackageDataReader(DataReader* dataReader,
const PackageData& data, PackageDataReader*& _reader)
{
PackageDataReader* reader;
switch (data.Compression()) {
case B_HPKG_COMPRESSION_NONE:
reader = new(std::nothrow) UncompressedPackageDataReader(
dataReader);
break;
case B_HPKG_COMPRESSION_ZLIB:
// TODO:...
return B_UNSUPPORTED;;
default:
return B_BAD_VALUE;
}
if (reader == NULL)
return B_NO_MEMORY;
status_t error = reader->Init(data);
if (error != B_OK) {
delete reader;
return error;
}
_reader = reader;
return B_OK;
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_DATA_READER_H
#define PACKAGE_DATA_READER_H
#include "DataReader.h"
class PackageData;
class PackageDataReader : public DataReader {
public:
PackageDataReader(DataReader* dataReader);
virtual ~PackageDataReader();
virtual status_t Init(const PackageData& data) = 0;
virtual uint64 Size() const = 0;
virtual size_t BlockSize() const = 0;
protected:
DataReader* fDataReader;
};
class PackageDataReaderFactory {
public:
static status_t CreatePackageDataReader(DataReader* dataReader,
const PackageData& data,
PackageDataReader*& _reader);
};
#endif // PACKAGE_DATA_READER_H

View File

@ -0,0 +1,24 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "PackageEntry.h"
PackageEntry::PackageEntry(PackageEntry* parent, const char* name)
:
fParent(parent),
fName(name),
fUserToken(NULL),
fMode(S_IFREG | S_IRUSR | S_IRGRP | S_IROTH),
fSymlinkPath(NULL)
{
fAccessTime.tv_sec = 0;
fAccessTime.tv_nsec = 0;
fModifiedTime.tv_sec = 0;
fModifiedTime.tv_nsec = 0;
fCreationTime.tv_sec = 0;
fCreationTime.tv_nsec = 0;
}

View File

@ -0,0 +1,84 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_ENTRY_H
#define PACKAGE_ENTRY_H
#include <sys/stat.h>
#include "PackageData.h"
class PackageEntry {
public:
PackageEntry(PackageEntry* parent,
const char* name);
const PackageEntry* Parent() const { return fParent; }
const char* Name() const { return fName; }
void* UserToken() const { return fUserToken; }
mode_t Mode() const { return fMode; }
const timespec& AccessTime() const
{ return fAccessTime; }
const timespec& ModifiedTime() const
{ return fModifiedTime; }
const timespec& CreationTime() const
{ return fCreationTime; }
PackageData& Data() { return fData; }
const char* SymlinkPath() const { return fSymlinkPath; }
void SetUserToken(void* token)
{ fUserToken = token; }
void SetType(uint32 type);
void SetPermissions(uint32 permissions);
void SetAccessTime(uint32 seconds)
{ fAccessTime.tv_sec = seconds; }
void SetAccessTimeNanos(uint32 nanos)
{ fAccessTime.tv_nsec = nanos; }
void SetModifiedTime(uint32 seconds)
{ fModifiedTime.tv_sec = seconds; }
void SetModifiedTimeNanos(uint32 nanos)
{ fModifiedTime.tv_nsec = nanos; }
void SetCreationTime(uint32 seconds)
{ fCreationTime.tv_sec = seconds; }
void SetCreationTimeNanos(uint32 nanos)
{ fCreationTime.tv_nsec = nanos; }
void SetSymlinkPath(const char* path)
{ fSymlinkPath = path; }
private:
PackageEntry* fParent;
const char* fName;
void* fUserToken;
mode_t fMode;
timespec fAccessTime;
timespec fModifiedTime;
timespec fCreationTime;
PackageData fData;
const char* fSymlinkPath;
};
inline void
PackageEntry::SetType(uint32 type)
{
fMode = (fMode & ~(uint32)S_IFMT) | (type & S_IFMT);
}
inline void
PackageEntry::SetPermissions(uint32 permissions)
{
fMode = (fMode & ~(uint32)ALLPERMS) | (permissions & ALLPERMS);
}
#endif // PACKAGE_ENTRY_H

View File

@ -0,0 +1,15 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "PackageEntryAttribute.h"
PackageEntryAttribute::PackageEntryAttribute(const char* name)
:
fName(name),
fType(0)
{
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_ENTRY_ATTRIBUTE_H
#define PACKAGE_ENTRY_ATTRIBUTE_H
#include "PackageData.h"
class PackageEntryAttribute {
public:
PackageEntryAttribute(const char* name);
const char* Name() const { return fName; }
uint32 Type() const { return fType; }
PackageData& Data() { return fData; }
void SetType(uint32 type) { fType = type; }
private:
const char* fName;
uint32 fType;
PackageData fData;
};
#endif // PACKAGE_ENTRY_ATTRIBUTE_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,155 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_READER_H
#define PACKAGE_READER_H
#include <SupportDefs.h>
#include <util/SinglyLinkedList.h>
#include "PackageAttributeValue.h"
class PackageEntry;
class PackageEntryAttribute;
class LowLevelPackageContentHandler {
public:
virtual ~LowLevelPackageContentHandler();
virtual status_t HandleAttribute(const char* attributeName,
const PackageAttributeValue& value,
void* parentToken, void*& _token) = 0;
virtual status_t HandleAttributeDone(const char* attributeName,
const PackageAttributeValue& value,
void* token) = 0;
virtual void HandleErrorOccurred() = 0;
};
class PackageContentHandler {
public:
virtual ~PackageContentHandler();
virtual status_t HandleEntry(PackageEntry* entry) = 0;
virtual status_t HandleEntryAttribute(PackageEntry* entry,
PackageEntryAttribute* attribute) = 0;
virtual status_t HandleEntryDone(PackageEntry* entry) = 0;
virtual void HandleErrorOccurred() = 0;
};
class PackageReader {
public:
PackageReader();
~PackageReader();
status_t Init(const char* fileName);
status_t ParseContent(
PackageContentHandler* contentHandler);
status_t ParseContent(
LowLevelPackageContentHandler*
contentHandler);
int PackageFileFD() { return fFD; }
private:
struct AttributeType;
struct AttributeTypeReference;
struct AttributeHandlerContext;
struct AttributeHandler;
struct IgnoreAttributeHandler;
struct DataAttributeHandler;
struct AttributeAttributeHandler;
struct EntryAttributeHandler;
struct RootAttributeHandler;
struct PackageAttributeHandler;
struct PackageContentListHandler;
typedef PackageAttributeValue AttributeValue;
typedef SinglyLinkedList<AttributeHandler> AttributeHandlerList;
private:
status_t _Init(const char* fileName);
const char* _CheckCompression(uint32 compression,
uint64 compressedLength,
uint64 uncompressedLength) const;
status_t _ParseTOCAttributeTypes();
status_t _ParseTOCStrings();
status_t _ParseContent(AttributeHandlerContext* context,
AttributeHandler* rootAttributeHandler);
status_t _ParseAttributeTree(
AttributeHandlerContext* context);
status_t _ReadAttributeValue(uint8 type, uint8 encoding,
AttributeValue& _value);
status_t _ReadUnsignedLEB128(uint64& _value);
status_t _ReadString(const char*& _string,
size_t* _stringLength = NULL);
template<typename Type>
inline status_t _Read(Type& _value);
status_t _GetTOCBuffer(size_t size,
const void*& _buffer);
status_t _ReadTOCBuffer(void* buffer, size_t size);
status_t _ReadBuffer(void* buffer, size_t size,
off_t offset);
static int8 _GetStandardIndex(const AttributeType* type);
inline AttributeHandler* _CurrentAttributeHandler() const;
inline void _PushAttributeHandler(
AttributeHandler* handler);
inline AttributeHandler* _PopAttributeHandler();
private:
int fFD;
uint64 fTotalSize;
uint64 fHeapOffset;
uint64 fHeapSize;
uint32 fTOCCompression;
uint64 fTOCCompressedLength;
uint64 fTOCUncompressedLength;
uint64 fTOCSectionOffset;
uint64 fTOCAttributeTypesLength;
uint64 fTOCAttributeTypesCount;
uint64 fTOCStringsLength;
uint64 fTOCStringsCount;
uint32 fPackageAttributesCompression;
uint32 fPackageAttributesCompressedLength;
uint32 fPackageAttributesUncompressedLength;
uint64 fPackageAttributesOffset;
uint8* fTOCSection;
uint64 fCurrentTOCOffset;
AttributeTypeReference* fAttributeTypes;
char** fStrings;
AttributeHandlerList* fAttributeHandlerStack;
};
template<typename Type>
status_t
PackageReader::_Read(Type& _value)
{
return _ReadTOCBuffer(&_value, sizeof(Type));
}
#endif // PACKAGE_READER_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,129 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_WRITER_H
#define PACKAGE_WRITER_H
#include <util/DoublyLinkedList.h>
#include <util/OpenHashTable.h>
#include "Strings.h"
class Data;
class PackageWriter {
public:
PackageWriter();
~PackageWriter();
status_t Init(const char* fileName);
status_t AddEntry(const char* fileName);
status_t Finish();
private:
struct AttributeValue;
struct AttributeTypeKey;
struct AttributeType;
struct AttributeTypeHashDefinition;
struct Attribute;
struct AttributeTypeUsageGreater;
struct Entry;
typedef BOpenHashTable<AttributeTypeHashDefinition>
AttributeTypeTable;
typedef DoublyLinkedList<Entry> EntryList;
private:
status_t _Init(const char* fileName);
status_t _Finish();
status_t _RegisterEntry(const char* fileName);
Entry* _RegisterEntry(Entry* parent,
const char* name, size_t nameLength,
bool isImplicit);
void _WriteAttributeTypes();
int32 _WriteCachedStrings();
void _WriteAttributeChildren(Attribute* attribute);
void _WriteAttributeValue(
const AttributeValue& value,
uint8 encoding);
void _WriteUnsignedLEB128(uint64 value);
inline void _WriteString(const char* string);
template<typename Type>
inline void _Write(const Type& value);
void _WriteBuffer(const void* buffer, size_t size,
off_t offset);
inline void _WriteBuffer(const void* buffer, size_t size);
void _AddEntry(int dirFD, Entry* entry,
const char* fileName);
Attribute* _AddAttribute(const char* attributeName,
const AttributeValue& value);
template<typename Type>
inline Attribute* _AddAttribute(const char* attributeName,
Type value);
Attribute* _AddStringAttribute(const char* attributeName,
const char* value);
Attribute* _AddDataAttribute(const char* attributeName,
uint64 dataSize, uint64 dataOffset);
CachedString* _GetCachedString(const char* value);
AttributeType* _GetAttributeType(const char* attributeName,
uint8 type);
status_t _AddData(Data& data, off_t size);
private:
const char* fFileName;
int fFD;
bool fFinished;
off_t fHeapOffset;
off_t fHeapEnd;
void* fDataBuffer;
size_t fDataBufferSize;
Entry* fRootEntry;
Attribute* fRootAttribute;
Attribute* fTopAttribute;
CachedStringTable* fCachedStrings;
AttributeTypeTable* fAttributeTypes;
};
template<typename Type>
inline void
PackageWriter::_Write(const Type& value)
{
_WriteBuffer(&value, sizeof(Type));
}
inline void
PackageWriter::_WriteString(const char* string)
{
_WriteBuffer(string, strlen(string) + 1);
}
inline void
PackageWriter::_WriteBuffer(const void* buffer, size_t size)
{
_WriteBuffer(buffer, size, fHeapEnd);
fHeapEnd += size;
}
#endif // PACKAGE_WRITER_H

40
src/bin/package/Stacker.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef STACKER_H
#define STACKER_H
template<typename Type>
class Stacker {
public:
Stacker(Type*& location, Type* element)
:
fLocation(&location),
fPreviousElement(location)
{
*fLocation = element;
}
Stacker(Type** location, Type* element)
:
fLocation(location),
fPreviousElement(*location)
{
*fLocation = element;
}
~Stacker()
{
if (fLocation != NULL)
*fLocation = fPreviousElement;
}
private:
Type** fLocation;
Type* fPreviousElement;
};
#endif // STACKER_H

View File

@ -0,0 +1,27 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "Strings.h"
// from the Dragon Book: a slightly modified hashpjw()
uint32
hash_string(const char* string)
{
if (string == NULL)
return 0;
uint32 h = 0;
for (; *string; string++) {
uint32 g = h & 0xf0000000;
if (g)
h ^= g >> 24;
h = (h << 4) + *string;
}
return h;
}

82
src/bin/package/Strings.h Normal file
View File

@ -0,0 +1,82 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef STRINGS_H
#define STRINGS_H
#include <util/OpenHashTable.h>
uint32 hash_string(const char* string);
struct CachedString {
char* string;
int32 index;
uint32 usageCount;
CachedString* next; // hash table link
CachedString()
:
string(NULL),
index(-1),
usageCount(1)
{
}
~CachedString()
{
free(string);
}
bool Init(const char* string)
{
this->string = strdup(string);
if (this->string == NULL)
return false;
return true;
}
};
struct CachedStringHashDefinition {
typedef const char* KeyType;
typedef CachedString ValueType;
size_t HashKey(const char* key) const
{
return hash_string(key);
}
size_t Hash(const CachedString* value) const
{
return HashKey(value->string);
}
bool Compare(const char* key, const CachedString* value) const
{
return strcmp(value->string, key) == 0;
}
CachedString*& GetLink(CachedString* value) const
{
return value->next;
}
};
typedef BOpenHashTable<CachedStringHashDefinition> CachedStringTable;
struct CachedStringUsageGreater {
bool operator()(const CachedString* a, const CachedString* b)
{
return a->usageCount > b->usageCount;
}
};
#endif // STRINGS_H

View File

@ -0,0 +1,90 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "package.h"
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "package.h"
#include "PackageWriter.h"
int
command_create(int argc, const char* const* argv)
{
const char* changeToDirectory = NULL;
while (true) {
static struct option sLongOptions[] = {
{ "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0 }
};
opterr = 0; // don't print errors
int c = getopt_long(argc, (char**)argv, "+C:h", sLongOptions, NULL);
if (c == -1)
break;
switch (c) {
case 'C':
changeToDirectory = optarg;
break;
case 'h':
print_usage_and_exit(false);
break;
default:
print_usage_and_exit(true);
break;
}
}
// The remaining arguments are the package file and the list of files to
// include, i.e. at least two more arguments.
if (optind + 2 > argc)
print_usage_and_exit(true);
const char* packageFileName = argv[optind++];
const char* const* fileNames = argv + optind;
int fileNameCount = argc - optind;
// create package
PackageWriter packageWriter;
status_t error = packageWriter.Init(packageFileName);
printf("Init(): %s\n", strerror(error));
if (error != B_OK)
return 1;
// change directory, if requested
if (changeToDirectory != NULL) {
if (chdir(changeToDirectory) != 0) {
fprintf(stderr, "Error: Failed to change the current working "
"directory to \"%s\": %s\n", changeToDirectory,
strerror(errno));
}
}
// add files
for (int i = 0; i < fileNameCount; i++) {
error = packageWriter.AddEntry(fileNames[i]);
printf("AddEntry(\"%s\"): %s\n", fileNames[i], strerror(error));
if (error != B_OK)
return 1;
}
// write the package
error = packageWriter.Finish();
printf("Finish(): %s\n", strerror(error));
if (error != B_OK)
return 1;
return 0;
}

View File

@ -0,0 +1,152 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "package.h"
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "package.h"
#include "PackageEntry.h"
#include "PackageEntryAttribute.h"
#include "PackageReader.h"
struct PackageContentDumpHandler : LowLevelPackageContentHandler {
PackageContentDumpHandler()
:
fLevel(0),
fErrorOccurred(false),
fHasChildren(false)
{
}
virtual status_t HandleAttribute(const char* attributeName,
const PackageAttributeValue& value, void* parentToken, void*& _token)
{
if (fErrorOccurred)
return B_OK;
printf("%*s>%s: ", fLevel * 2, "", attributeName);
_PrintValue(value);
printf("\n");
fHasChildren = false;
fLevel++;
return B_OK;
}
virtual status_t HandleAttributeDone(const char* attributeName,
const PackageAttributeValue& value, void* token)
{
if (fErrorOccurred)
return B_OK;
fLevel--;
if (fHasChildren)
printf("%*s<%s\n", fLevel * 2, "", attributeName);
fHasChildren = true;
return B_OK;
}
virtual void HandleErrorOccurred()
{
fErrorOccurred = true;
}
private:
void _PrintValue(const PackageAttributeValue& value)
{
switch (value.type) {
case B_HPKG_ATTRIBUTE_TYPE_INT:
printf("%lld (%#llx)", value.signedInt, value.signedInt);
break;
case B_HPKG_ATTRIBUTE_TYPE_UINT:
printf("%llu (%#llx)", value.unsignedInt, value.unsignedInt);
break;
case B_HPKG_ATTRIBUTE_TYPE_STRING:
printf("\"%s\"", value.string);
break;
case B_HPKG_ATTRIBUTE_TYPE_RAW:
switch (value.encoding) {
case B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE:
printf("data: size: %llu, inline", value.data.size);
// TODO: Print the data bytes!
break;
case B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP:
printf("data: size: %llu, offset: %llu",
value.data.size, value.data.offset);
break;
default:
break;
}
break;
default:
printf("<unknown type %u>\n", value.type);
break;
}
}
private:
int fLevel;
bool fErrorOccurred;
bool fHasChildren;
};
int
command_dump(int argc, const char* const* argv)
{
while (true) {
static struct option sLongOptions[] = {
{ "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0 }
};
opterr = 0; // don't print errors
int c = getopt_long(argc, (char**)argv, "+h", sLongOptions, NULL);
if (c == -1)
break;
switch (c) {
case 'h':
print_usage_and_exit(false);
break;
default:
print_usage_and_exit(true);
break;
}
}
// One argument should remain -- the package file name.
if (optind + 1 != argc)
print_usage_and_exit(true);
const char* packageFileName = argv[optind++];
// open package
PackageReader packageReader;
status_t error = packageReader.Init(packageFileName);
printf("Init(): %s\n", strerror(error));
if (error != B_OK)
return 1;
// list
PackageContentDumpHandler handler;
error = packageReader.ParseContent(&handler);
printf("ParseContent(): %s\n", strerror(error));
if (error != B_OK)
return 1;
return 0;
}

View File

@ -0,0 +1,358 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "package.h"
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <algorithm>
#include <new>
#include <fs_attr.h>
#include <AutoDeleter.h>
#include "FDCloser.h"
#include "package.h"
#include "PackageDataReader.h"
#include "PackageEntry.h"
#include "PackageEntryAttribute.h"
#include "PackageReader.h"
struct PackageContentExtractHandler : PackageContentHandler {
PackageContentExtractHandler(int packageFileFD)
:
fPackageFileReader(packageFileFD),
fDataBuffer(NULL),
fDataBufferSize(0),
fErrorOccurred(false)
{
}
~PackageContentExtractHandler()
{
free(fDataBuffer);
}
status_t Init()
{
fDataBufferSize = 64 * 1024;
fDataBuffer = malloc(fDataBufferSize);
if (fDataBuffer == NULL)
return B_NO_MEMORY;
return B_OK;
}
virtual status_t HandleEntry(PackageEntry* entry)
{
// create a token
Token* token = new(std::nothrow) Token;
if (token == NULL)
return B_NO_MEMORY;
ObjectDeleter<Token> tokenDeleter(token);
// get parent FD
int parentFD = AT_FDCWD;
if (entry->Parent() != NULL)
parentFD = ((Token*)entry->Parent()->UserToken())->fd;
// check whether something is in the way
struct stat st;
bool entryExists = fstatat(parentFD, entry->Name(), &st,
AT_SYMLINK_NOFOLLOW) == 0;
if (entryExists) {
if (S_ISREG(entry->Mode()) || S_ISLNK(entry->Mode())) {
// If the entry in the way is a regular file or a symlink,
// remove it, otherwise fail.
if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
fprintf(stderr, "Error: Can't create entry \"%s\", since "
"something is in the way\n", entry->Name());
return B_FILE_EXISTS;
}
if (unlinkat(parentFD, entry->Name(), 0) != 0) {
fprintf(stderr, "Error: Failed to unlink entry \"%s\": %s\n",
entry->Name(), strerror(errno));
return errno;
}
entryExists = false;
} else if (S_ISDIR(entry->Mode())) {
// If the entry in the way is a directory, merge, otherwise
// fail.
if (!S_ISDIR(st.st_mode)) {
fprintf(stderr, "Error: Can't create directory \"%s\", "
"since something is in the way\n", entry->Name());
return B_FILE_EXISTS;
}
}
}
// create the entry
int fd = -1;
if (S_ISREG(entry->Mode())) {
// create the file
fd = openat(parentFD, entry->Name(), O_RDWR | O_CREAT | O_EXCL,
entry->Mode() & ALLPERMS);
if (fd < 0) {
fprintf(stderr, "Error: Failed to create file \"%s\": %s\n",
entry->Name(), strerror(errno));
return errno;
}
// write data
status_t error;
const PackageData& data = entry->Data();
if (data.IsEncodedInline()) {
BufferDataReader dataReader(data.InlineData(),
data.CompressedSize());
error = _ExtractFileData(&dataReader, data, fd);
} else
error = _ExtractFileData(&fPackageFileReader, data, fd);
if (error != B_OK)
return error;
} else if (S_ISLNK(entry->Mode())) {
// create the symlink
const char* symlinkPath = entry->SymlinkPath();
if (symlinkat(symlinkPath != NULL ? symlinkPath : "", parentFD,
entry->Name()) != 0) {
fprintf(stderr, "Error: Failed to create symlink \"%s\": %s\n",
entry->Name(), strerror(errno));
return errno;
}
// TODO: Set symlink permissions?
} else if (S_ISDIR(entry->Mode())) {
// create the directory, if necessary
if (!entryExists
&& mkdirat(parentFD, entry->Name(), entry->Mode() & ALLPERMS)
!= 0) {
fprintf(stderr, "Error: Failed to create directory \"%s\": "
"%s\n", entry->Name(), strerror(errno));
return errno;
}
} else {
fprintf(stderr, "Error: Invalid file type for entry \"%s\"\n",
entry->Name());
return B_BAD_DATA;
}
// If not done yet (symlink, dir), open the node -- we need the FD.
if (fd < 0) {
fd = openat(parentFD, entry->Name(), O_RDONLY | O_NOTRAVERSE);
if (fd < 0) {
fprintf(stderr, "Error: Failed to open entry \"%s\": %s\n",
entry->Name(), strerror(errno));
return errno;
}
}
token->fd = fd;
// set the file times
if (!entryExists) {
timespec times[2] = {entry->AccessTime(), entry->ModifiedTime()};
futimens(fd, times);
// set user/group
// TODO:...
}
entry->SetUserToken(tokenDeleter.Detach());
return B_OK;
}
virtual status_t HandleEntryAttribute(PackageEntry* entry,
PackageEntryAttribute* attribute)
{
int entryFD = ((Token*)entry->UserToken())->fd;
// create the attribute
int fd = fs_fopen_attr(entryFD, attribute->Name(), attribute->Type(),
O_WRONLY | O_CREAT | O_TRUNC);
if (fd < 0) {
fprintf(stderr, "Error: Failed to create attribute \"%s\" of "
"file \"%s\": %s\n", attribute->Name(), entry->Name(),
strerror(errno));
return errno;
}
FDCloser fdCloser(fd);
// write data
status_t error;
const PackageData& data = attribute->Data();
if (data.IsEncodedInline()) {
BufferDataReader dataReader(data.InlineData(),
data.CompressedSize());
error = _ExtractFileData(&dataReader, data, fd);
} else
error = _ExtractFileData(&fPackageFileReader, data, fd);
if (error != B_OK)
return error;
return B_OK;
}
virtual status_t HandleEntryDone(PackageEntry* entry)
{
if (Token* token = (Token*)entry->UserToken()) {
delete token;
entry->SetUserToken(NULL);
}
return B_OK;
}
virtual void HandleErrorOccurred()
{
fErrorOccurred = true;
}
private:
struct Token {
int fd;
Token()
:
fd(-1)
{
}
~Token()
{
if (fd >= 0)
close(fd);
}
};
private:
status_t _ExtractFileData(DataReader* dataReader, const PackageData& data,
int fd)
{
// create a PackageDataReader
PackageDataReader* reader;
status_t error = PackageDataReaderFactory::CreatePackageDataReader(
dataReader, data, reader);
if (error != B_OK)
return error;
ObjectDeleter<PackageDataReader> readerDeleter(reader);
// write the data
off_t bytesRemaining = data.UncompressedSize();
off_t offset = 0;
while (bytesRemaining > 0) {
// read
size_t toCopy = std::min((off_t)fDataBufferSize, bytesRemaining);
error = reader->ReadData(offset, fDataBuffer, toCopy);
if (error != B_OK) {
fprintf(stderr, "Error: Failed to read data: %s\n",
strerror(errno));
return error;
}
// write
ssize_t bytesWritten = pwrite(fd, fDataBuffer, toCopy, offset);
if (bytesWritten < 0) {
fprintf(stderr, "Error: Failed to write data: %s\n",
strerror(errno));
return errno;
}
if ((size_t)bytesWritten != toCopy) {
fprintf(stderr, "Error: Failed to write all data\n");
return B_ERROR;
}
offset += toCopy;
bytesRemaining -= toCopy;
}
return B_OK;
}
private:
FDDataReader fPackageFileReader;
void* fDataBuffer;
size_t fDataBufferSize;
bool fErrorOccurred;
};
int
command_extract(int argc, const char* const* argv)
{
const char* changeToDirectory = NULL;
while (true) {
static struct option sLongOptions[] = {
{ "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0 }
};
opterr = 0; // don't print errors
int c = getopt_long(argc, (char**)argv, "+C:h", sLongOptions, NULL);
if (c == -1)
break;
switch (c) {
case 'C':
changeToDirectory = optarg;
break;
case 'h':
print_usage_and_exit(false);
break;
default:
print_usage_and_exit(true);
break;
}
}
// One argument should remain -- the package file name.
if (optind + 1 != argc)
print_usage_and_exit(true);
const char* packageFileName = argv[optind++];
// open package
PackageReader packageReader;
status_t error = packageReader.Init(packageFileName);
printf("Init(): %s\n", strerror(error));
if (error != B_OK)
return 1;
// change directory, if requested
if (changeToDirectory != NULL) {
if (chdir(changeToDirectory) != 0) {
fprintf(stderr, "Error: Failed to change the current working "
"directory to \"%s\": %s\n", changeToDirectory,
strerror(errno));
}
}
// extract
PackageContentExtractHandler handler(packageReader.PackageFileFD());
error = handler.Init();
if (error != B_OK)
return 1;
error = packageReader.ParseContent(&handler);
printf("ParseContent(): %s\n", strerror(error));
if (error != B_OK)
return 1;
return 0;
}

View File

@ -0,0 +1,180 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "package.h"
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "package.h"
#include "PackageEntry.h"
#include "PackageEntryAttribute.h"
#include "PackageReader.h"
struct PackageContentListHandler : PackageContentHandler {
PackageContentListHandler(bool listAttributes)
:
fLevel(0),
fListAttribute(listAttributes)
{
}
virtual status_t HandleEntry(PackageEntry* entry)
{
fLevel++;
int indentation = (fLevel - 1) * 2;
printf("%*s", indentation, "");
// name and size
printf("%-*s", indentation < 32 ? 32 - indentation : 0, entry->Name());
printf(" %8llu", entry->Data().UncompressedSize());
// time
struct tm* time = localtime(&entry->ModifiedTime().tv_sec);
printf(" %04d-%02d-%02d %02d:%02d:%02d",
1900 + time->tm_year, time->tm_mon + 1, time->tm_mday,
time->tm_hour, time->tm_min, time->tm_sec);
// file type
mode_t mode = entry->Mode();
if (S_ISREG(mode))
printf(" -");
else if (S_ISDIR(mode))
printf(" d");
else if (S_ISLNK(mode))
printf(" l");
else
printf(" ?");
// permissions
char buffer[4];
printf("%s", _PermissionString(buffer, mode >> 6,
(mode & S_ISUID) != 0));
printf("%s", _PermissionString(buffer, mode >> 3,
(mode & S_ISGID) != 0));
printf("%s", _PermissionString(buffer, mode, false));
// print the symlink path
if (S_ISLNK(mode))
printf(" -> %s", entry->SymlinkPath());
printf("\n");
return B_OK;
}
virtual status_t HandleEntryAttribute(PackageEntry* entry,
PackageEntryAttribute* attribute)
{
if (!fListAttribute)
return B_OK;
int indentation = fLevel * 2;
printf("%*s<", indentation, "");
printf("%-*s %8llu", indentation < 31 ? 31 - indentation : 0,
attribute->Name(), attribute->Data().UncompressedSize());
uint32 type = attribute->Type();
if (isprint(type & 0xff) && isprint((type >> 8) & 0xff)
&& isprint((type >> 16) & 0xff) && isprint(type >> 24)) {
printf(" '%c%c%c%c'", int(type >> 24), int((type >> 16) & 0xff),
int((type >> 8) & 0xff), int(type & 0xff));
} else
printf(" %#lx", type);
printf(">\n");
return B_OK;
}
virtual status_t HandleEntryDone(PackageEntry* entry)
{
fLevel--;
return B_OK;
}
virtual void HandleErrorOccurred()
{
}
private:
static const char* _PermissionString(char* buffer, uint32 mode, bool sticky)
{
buffer[0] = (mode & 0x4) != 0 ? 'r' : '-';
buffer[1] = (mode & 0x2) != 0 ? 'w' : '-';
if ((mode & 0x1) != 0)
buffer[2] = sticky ? 's' : 'x';
else
buffer[2] = '-';
buffer[3] = '\0';
return buffer;
}
private:
int fLevel;
bool fListAttribute;
};
int
command_list(int argc, const char* const* argv)
{
bool listAttributes = false;
while (true) {
static struct option sLongOptions[] = {
{ "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0 }
};
opterr = 0; // don't print errors
int c = getopt_long(argc, (char**)argv, "+ha", sLongOptions, NULL);
if (c == -1)
break;
switch (c) {
case 'a':
listAttributes = true;
break;
case 'h':
print_usage_and_exit(false);
break;
default:
print_usage_and_exit(true);
break;
}
}
// One argument should remain -- the package file name.
if (optind + 1 != argc)
print_usage_and_exit(true);
const char* packageFileName = argv[optind++];
// open package
PackageReader packageReader;
status_t error = packageReader.Init(packageFileName);
printf("Init(): %s\n", strerror(error));
if (error != B_OK)
return 1;
// list
PackageContentListHandler handler(listAttributes);
error = packageReader.ParseContent(&handler);
printf("ParseContent(): %s\n", strerror(error));
if (error != B_OK)
return 1;
return 0;
}

View File

@ -0,0 +1,87 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "package.h"
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "PackageWriter.h"
extern const char* __progname;
const char* kCommandName = __progname;
static const char* kUsage =
"Usage: %s <command> <command args>\n"
"Creates, inspects, or extracts a Haiku package.\n"
"\n"
"Commands:\n"
" create [ <options> ] <package> <file> ...\n"
" Creates package file <package> from a list of files.\n"
"\n"
" -C <dir> - Change to directory <dir> before interpreting the file\n"
" names <file>.\n"
"\n"
" dump [ <options> ] <package>\n"
" Dumps the TOC section of package file <package>. For debugging only.\n"
"\n"
" extract [ <options> ] <package>\n"
" Extracts the contents of package file <package>.\n"
"\n"
" -C <dir> - Change to directory <dir> before extracting the "
"contents\n"
" of the archive.\n"
"\n"
" list [ <options> ] <package>\n"
" Lists the contents of package file <package>.\n"
"\n"
" -a - Also list the file attributes.\n"
"\n"
"Common Options:\n"
" -h, --help - Print this usage info.\n"
;
void
print_usage_and_exit(bool error)
{
fprintf(error ? stderr : stdout, kUsage, kCommandName);
exit(error ? 1 : 0);
}
int
main(int argc, const char* const* argv)
{
if (argc < 2)
print_usage_and_exit(true);
const char* command = argv[1];
if (strcmp(command, "create") == 0)
return command_create(argc - 1, argv + 1);
if (strcmp(command, "dump") == 0)
return command_dump(argc - 1, argv + 1);
if (strcmp(command, "extract") == 0)
return command_extract(argc - 1, argv + 1);
if (strcmp(command, "list") == 0)
return command_list(argc - 1, argv + 1);
if (strcmp(command, "help") == 0)
print_usage_and_exit(false);
else
print_usage_and_exit(true);
// never gets here
return 0;
}

17
src/bin/package/package.h Normal file
View File

@ -0,0 +1,17 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_H
#define PACKAGE_H
void print_usage_and_exit(bool error);
int command_create(int argc, const char* const* argv);
int command_dump(int argc, const char* const* argv);
int command_extract(int argc, const char* const* argv);
int command_list(int argc, const char* const* argv);
#endif // PACKAGE_H