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:
parent
8735f4fde6
commit
050aa61bd6
155
headers/private/haiku_package/haiku_package.h
Normal file
155
headers/private/haiku_package/haiku_package.h
Normal 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
|
@ -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 ;
|
||||
|
67
src/bin/package/DataReader.cpp
Normal file
67
src/bin/package/DataReader.cpp
Normal 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;
|
||||
}
|
46
src/bin/package/DataReader.h
Normal file
46
src/bin/package/DataReader.h
Normal 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
|
27
src/bin/package/FDCloser.h
Normal file
27
src/bin/package/FDCloser.h
Normal 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
25
src/bin/package/Jamfile
Normal 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++)
|
||||
;
|
147
src/bin/package/PackageAttributeValue.h
Normal file
147
src/bin/package/PackageAttributeValue.h
Normal 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
|
38
src/bin/package/PackageData.cpp
Normal file
38
src/bin/package/PackageData.cpp
Normal 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;
|
||||
}
|
47
src/bin/package/PackageData.h
Normal file
47
src/bin/package/PackageData.h
Normal 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
|
112
src/bin/package/PackageDataReader.cpp
Normal file
112
src/bin/package/PackageDataReader.cpp
Normal 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;
|
||||
}
|
38
src/bin/package/PackageDataReader.h
Normal file
38
src/bin/package/PackageDataReader.h
Normal 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
|
24
src/bin/package/PackageEntry.cpp
Normal file
24
src/bin/package/PackageEntry.cpp
Normal 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;
|
||||
}
|
84
src/bin/package/PackageEntry.h
Normal file
84
src/bin/package/PackageEntry.h
Normal 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
|
15
src/bin/package/PackageEntryAttribute.cpp
Normal file
15
src/bin/package/PackageEntryAttribute.cpp
Normal 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)
|
||||
{
|
||||
}
|
30
src/bin/package/PackageEntryAttribute.h
Normal file
30
src/bin/package/PackageEntryAttribute.h
Normal 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
|
1276
src/bin/package/PackageReader.cpp
Normal file
1276
src/bin/package/PackageReader.cpp
Normal file
File diff suppressed because it is too large
Load Diff
155
src/bin/package/PackageReader.h
Normal file
155
src/bin/package/PackageReader.h
Normal 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
|
1196
src/bin/package/PackageWriter.cpp
Normal file
1196
src/bin/package/PackageWriter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
129
src/bin/package/PackageWriter.h
Normal file
129
src/bin/package/PackageWriter.h
Normal 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
40
src/bin/package/Stacker.h
Normal 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
|
27
src/bin/package/Strings.cpp
Normal file
27
src/bin/package/Strings.cpp
Normal 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
82
src/bin/package/Strings.h
Normal 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
|
90
src/bin/package/command_create.cpp
Normal file
90
src/bin/package/command_create.cpp
Normal 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;
|
||||
}
|
152
src/bin/package/command_dump.cpp
Normal file
152
src/bin/package/command_dump.cpp
Normal 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;
|
||||
}
|
358
src/bin/package/command_extract.cpp
Normal file
358
src/bin/package/command_extract.cpp
Normal 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;
|
||||
}
|
180
src/bin/package/command_list.cpp
Normal file
180
src/bin/package/command_list.cpp
Normal 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;
|
||||
}
|
87
src/bin/package/package.cpp
Normal file
87
src/bin/package/package.cpp
Normal 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
17
src/bin/package/package.h
Normal 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
|
Loading…
Reference in New Issue
Block a user