Add boot loader packagefs support
* Add pread(). * Add Node::ReadLink() to read a symbolic link path. * Add Directory::LookupDontTraverse() and make Lookup() non-abstract. Lookup() is implemented via LookupDontTraverse() and Node::ReadLink(). * Adjust all FS implementations accordingly. * Add a packagefs implementation. Unlike other FS implementations it isn't a pseudo-module, but provides a function to explicitly mount a package file (packagefs_mount_file()). * Finish BootVolume::SetTo() implementation, mounting the package file and replacing fSystemDirectory. Now the boot loader can load the kernel and boot modules from a packaged system. The kernel boots up to the point where the boot volume is mounted.
This commit is contained in:
@@ -26,8 +26,12 @@ class Node : public DoublyLinkedListLinkImpl<Node> {
|
|||||||
virtual status_t Open(void **_cookie, int mode);
|
virtual status_t Open(void **_cookie, int mode);
|
||||||
virtual status_t Close(void *cookie);
|
virtual status_t Close(void *cookie);
|
||||||
|
|
||||||
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) = 0;
|
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer,
|
||||||
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) = 0;
|
size_t bufferSize) = 0;
|
||||||
|
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer,
|
||||||
|
size_t bufferSize) = 0;
|
||||||
|
|
||||||
|
virtual status_t ReadLink(char* buffer, size_t bufferSize);
|
||||||
|
|
||||||
virtual status_t GetName(char *nameBuffer, size_t bufferSize) const;
|
virtual status_t GetName(char *nameBuffer, size_t bufferSize) const;
|
||||||
virtual status_t GetFileMap(struct file_map_run *runs, int32 *count);
|
virtual status_t GetFileMap(struct file_map_run *runs, int32 *count);
|
||||||
@@ -55,7 +59,8 @@ class Directory : public Node {
|
|||||||
|
|
||||||
virtual int32 Type() const;
|
virtual int32 Type() const;
|
||||||
|
|
||||||
virtual Node *Lookup(const char *name, bool traverseLinks) = 0;
|
virtual Node* Lookup(const char* name, bool traverseLinks);
|
||||||
|
virtual Node* LookupDontTraverse(const char* name) = 0;
|
||||||
|
|
||||||
virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize) = 0;
|
virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize) = 0;
|
||||||
virtual status_t GetNextNode(void *cookie, Node **_node) = 0;
|
virtual status_t GetNextNode(void *cookie, Node **_node) = 0;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ RootFileSystem::~RootFileSystem()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
RootFileSystem::Open(void **_cookie, int mode)
|
RootFileSystem::Open(void **_cookie, int mode)
|
||||||
{
|
{
|
||||||
EntryIterator *iterator = new (std::nothrow) EntryIterator(&fList);
|
EntryIterator *iterator = new (std::nothrow) EntryIterator(&fList);
|
||||||
@@ -42,7 +42,7 @@ RootFileSystem::Open(void **_cookie, int mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
RootFileSystem::Close(void *cookie)
|
RootFileSystem::Close(void *cookie)
|
||||||
{
|
{
|
||||||
delete (EntryIterator *)cookie;
|
delete (EntryIterator *)cookie;
|
||||||
@@ -50,8 +50,8 @@ RootFileSystem::Close(void *cookie)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Node *
|
Node*
|
||||||
RootFileSystem::Lookup(const char *name, bool /*traverseLinks*/)
|
RootFileSystem::LookupDontTraverse(const char* name)
|
||||||
{
|
{
|
||||||
EntryIterator iterator = fLinks.GetIterator();
|
EntryIterator iterator = fLinks.GetIterator();
|
||||||
struct entry *entry;
|
struct entry *entry;
|
||||||
@@ -84,7 +84,7 @@ RootFileSystem::Lookup(const char *name, bool /*traverseLinks*/)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
RootFileSystem::GetNextEntry(void *_cookie, char *name, size_t size)
|
RootFileSystem::GetNextEntry(void *_cookie, char *name, size_t size)
|
||||||
{
|
{
|
||||||
EntryIterator *iterator = (EntryIterator *)_cookie;
|
EntryIterator *iterator = (EntryIterator *)_cookie;
|
||||||
@@ -98,7 +98,7 @@ RootFileSystem::GetNextEntry(void *_cookie, char *name, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
RootFileSystem::GetNextNode(void *_cookie, Node **_node)
|
RootFileSystem::GetNextNode(void *_cookie, Node **_node)
|
||||||
{
|
{
|
||||||
EntryIterator *iterator = (EntryIterator *)_cookie;
|
EntryIterator *iterator = (EntryIterator *)_cookie;
|
||||||
@@ -113,24 +113,24 @@ RootFileSystem::GetNextNode(void *_cookie, Node **_node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
RootFileSystem::Rewind(void *_cookie)
|
RootFileSystem::Rewind(void *_cookie)
|
||||||
{
|
{
|
||||||
EntryIterator *iterator = (EntryIterator *)_cookie;
|
EntryIterator *iterator = (EntryIterator *)_cookie;
|
||||||
|
|
||||||
iterator->Rewind();
|
iterator->Rewind();
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RootFileSystem::IsEmpty()
|
RootFileSystem::IsEmpty()
|
||||||
{
|
{
|
||||||
return fList.IsEmpty();
|
return fList.IsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
RootFileSystem::AddVolume(Directory *volume, Partition *partition)
|
RootFileSystem::AddVolume(Directory *volume, Partition *partition)
|
||||||
{
|
{
|
||||||
struct entry *entry = new (std::nothrow) RootFileSystem::entry();
|
struct entry *entry = new (std::nothrow) RootFileSystem::entry();
|
||||||
@@ -165,7 +165,7 @@ RootFileSystem::AddLink(const char *name, Directory *target)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
RootFileSystem::GetPartitionFor(Directory *volume, Partition **_partition)
|
RootFileSystem::GetPartitionFor(Directory *volume, Partition **_partition)
|
||||||
{
|
{
|
||||||
EntryIterator iterator = fList.GetIterator();
|
EntryIterator iterator = fList.GetIterator();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class RootFileSystem : public Directory {
|
|||||||
virtual status_t Open(void **_cookie, int mode);
|
virtual status_t Open(void **_cookie, int mode);
|
||||||
virtual status_t Close(void *cookie);
|
virtual status_t Close(void *cookie);
|
||||||
|
|
||||||
virtual Node *Lookup(const char *name, bool traverseLinks);
|
virtual Node* LookupDontTraverse(const char* name);
|
||||||
|
|
||||||
virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize);
|
virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize);
|
||||||
virtual status_t GetNextNode(void *cookie, Node **_node);
|
virtual status_t GetNextNode(void *cookie, Node **_node);
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ SubInclude HAIKU_TOP src system boot loader file_systems amiga_ffs ;
|
|||||||
SubInclude HAIKU_TOP src system boot loader file_systems bfs ;
|
SubInclude HAIKU_TOP src system boot loader file_systems bfs ;
|
||||||
SubInclude HAIKU_TOP src system boot loader file_systems fat ;
|
SubInclude HAIKU_TOP src system boot loader file_systems fat ;
|
||||||
SubInclude HAIKU_TOP src system boot loader file_systems hfs_plus ;
|
SubInclude HAIKU_TOP src system boot loader file_systems hfs_plus ;
|
||||||
|
SubInclude HAIKU_TOP src system boot loader file_systems packagefs ;
|
||||||
SubInclude HAIKU_TOP src system boot loader file_systems tarfs ;
|
SubInclude HAIKU_TOP src system boot loader file_systems tarfs ;
|
||||||
|
|||||||
@@ -45,14 +45,14 @@ Directory::~Directory()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Directory::InitCheck()
|
Directory::InitCheck()
|
||||||
{
|
{
|
||||||
return fNode.ValidateCheckSum();
|
return fNode.ValidateCheckSum();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Directory::Open(void **_cookie, int mode)
|
Directory::Open(void **_cookie, int mode)
|
||||||
{
|
{
|
||||||
_inherited::Open(_cookie, mode);
|
_inherited::Open(_cookie, mode);
|
||||||
@@ -71,7 +71,7 @@ Directory::Open(void **_cookie, int mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Directory::Close(void *cookie)
|
Directory::Close(void *cookie)
|
||||||
{
|
{
|
||||||
_inherited::Close(cookie);
|
_inherited::Close(cookie);
|
||||||
@@ -81,8 +81,8 @@ Directory::Close(void *cookie)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Node *
|
Node*
|
||||||
Directory::Lookup(const char *name, bool traverseLinks)
|
Directory::LookupDontTraverse(const char* name)
|
||||||
{
|
{
|
||||||
if (!strcmp(name, ".")) {
|
if (!strcmp(name, ".")) {
|
||||||
Acquire();
|
Acquire();
|
||||||
@@ -113,7 +113,7 @@ Directory::Lookup(const char *name, bool traverseLinks)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Directory::GetNextEntry(void *cookie, char *name, size_t size)
|
Directory::GetNextEntry(void *cookie, char *name, size_t size)
|
||||||
{
|
{
|
||||||
HashIterator *iterator = (HashIterator *)cookie;
|
HashIterator *iterator = (HashIterator *)cookie;
|
||||||
@@ -127,7 +127,7 @@ Directory::GetNextEntry(void *cookie, char *name, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Directory::GetNextNode(void *cookie, Node **_node)
|
Directory::GetNextNode(void *cookie, Node **_node)
|
||||||
{
|
{
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class Directory : public ::Directory {
|
|||||||
virtual status_t Open(void **_cookie, int mode);
|
virtual status_t Open(void **_cookie, int mode);
|
||||||
virtual status_t Close(void *cookie);
|
virtual status_t Close(void *cookie);
|
||||||
|
|
||||||
virtual Node *Lookup(const char *name, bool traverseLinks);
|
virtual Node* LookupDontTraverse(const char* name);
|
||||||
|
|
||||||
virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize);
|
virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize);
|
||||||
virtual status_t GetNextNode(void *cookie, Node **_node);
|
virtual status_t GetNextNode(void *cookie, Node **_node);
|
||||||
|
|||||||
@@ -52,14 +52,14 @@ Directory::~Directory()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Directory::InitCheck()
|
Directory::InitCheck()
|
||||||
{
|
{
|
||||||
return fStream.InitCheck();
|
return fStream.InitCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Directory::Open(void **_cookie, int mode)
|
Directory::Open(void **_cookie, int mode)
|
||||||
{
|
{
|
||||||
_inherited::Open(_cookie, mode);
|
_inherited::Open(_cookie, mode);
|
||||||
@@ -72,7 +72,7 @@ Directory::Open(void **_cookie, int mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Directory::Close(void *cookie)
|
Directory::Close(void *cookie)
|
||||||
{
|
{
|
||||||
_inherited::Close(cookie);
|
_inherited::Close(cookie);
|
||||||
@@ -82,43 +82,18 @@ Directory::Close(void *cookie)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Node *
|
Node*
|
||||||
Directory::Lookup(const char *name, bool traverseLinks)
|
Directory::LookupDontTraverse(const char* name)
|
||||||
{
|
{
|
||||||
off_t id;
|
off_t id;
|
||||||
if (fTree.Find((uint8 *)name, strlen(name), &id) < B_OK)
|
if (fTree.Find((uint8 *)name, strlen(name), &id) < B_OK)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
Node *node = Stream::NodeFactory(fStream.GetVolume(), id);
|
return Stream::NodeFactory(fStream.GetVolume(), id);
|
||||||
if (!node)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (S_ISLNK(node->Type())) {
|
|
||||||
// the node is a symbolic link, so we have to resolve the path
|
|
||||||
char linkPath[B_PATH_NAME_LENGTH];
|
|
||||||
((Link *)node)->ReadLink(linkPath, sizeof(linkPath));
|
|
||||||
|
|
||||||
delete node;
|
|
||||||
// we don't need this one anymore
|
|
||||||
|
|
||||||
int fd = open_from(this, linkPath, O_RDONLY);
|
|
||||||
if (fd >= 0) {
|
|
||||||
node = get_node_from(fd);
|
|
||||||
if (node != NULL)
|
|
||||||
node->Acquire();
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Directory::GetNextEntry(void *cookie, char *name, size_t size)
|
Directory::GetNextEntry(void *cookie, char *name, size_t size)
|
||||||
{
|
{
|
||||||
TreeIterator *iterator = (TreeIterator *)cookie;
|
TreeIterator *iterator = (TreeIterator *)cookie;
|
||||||
@@ -129,7 +104,7 @@ Directory::GetNextEntry(void *cookie, char *name, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Directory::GetNextNode(void *cookie, Node **_node)
|
Directory::GetNextNode(void *cookie, Node **_node)
|
||||||
{
|
{
|
||||||
TreeIterator *iterator = (TreeIterator *)cookie;
|
TreeIterator *iterator = (TreeIterator *)cookie;
|
||||||
@@ -149,7 +124,7 @@ Directory::GetNextNode(void *cookie, Node **_node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Directory::Rewind(void *cookie)
|
Directory::Rewind(void *cookie)
|
||||||
{
|
{
|
||||||
TreeIterator *iterator = (TreeIterator *)cookie;
|
TreeIterator *iterator = (TreeIterator *)cookie;
|
||||||
@@ -158,7 +133,7 @@ Directory::Rewind(void *cookie)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Directory::IsEmpty()
|
Directory::IsEmpty()
|
||||||
{
|
{
|
||||||
TreeIterator iterator(&fTree);
|
TreeIterator iterator(&fTree);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class Directory : public ::Directory {
|
|||||||
virtual status_t Open(void **_cookie, int mode);
|
virtual status_t Open(void **_cookie, int mode);
|
||||||
virtual status_t Close(void *cookie);
|
virtual status_t Close(void *cookie);
|
||||||
|
|
||||||
virtual Node *Lookup(const char *name, bool traverseLinks);
|
virtual Node* LookupDontTraverse(const char* name);
|
||||||
|
|
||||||
virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize);
|
virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize);
|
||||||
virtual status_t GetNextNode(void *cookie, Node **_node);
|
virtual status_t GetNextNode(void *cookie, Node **_node);
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ class Link : public File {
|
|||||||
Link(const Stream &stream);
|
Link(const Stream &stream);
|
||||||
|
|
||||||
status_t InitCheck();
|
status_t InitCheck();
|
||||||
status_t ReadLink(char *buffer, size_t bufferSize);
|
|
||||||
|
virtual status_t ReadLink(char *buffer, size_t bufferSize);
|
||||||
|
|
||||||
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
|
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
|
||||||
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
|
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
|
||||||
|
|||||||
@@ -351,10 +351,10 @@ Directory::Close(void *cookie)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Node *
|
Node*
|
||||||
Directory::Lookup(const char *name, bool traverseLinks)
|
Directory::LookupDontTraverse(const char* name)
|
||||||
{
|
{
|
||||||
TRACE(("FASFS::Directory::%s('%s', %d)\n", __FUNCTION__, name, traverseLinks));
|
TRACE(("FASFS::Directory::%s('%s')\n", __FUNCTION__, name));
|
||||||
if (!strcmp(name, ".")) {
|
if (!strcmp(name, ".")) {
|
||||||
Acquire();
|
Acquire();
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class Directory : public ::Directory {
|
|||||||
virtual status_t Open(void **_cookie, int mode);
|
virtual status_t Open(void **_cookie, int mode);
|
||||||
virtual status_t Close(void *cookie);
|
virtual status_t Close(void *cookie);
|
||||||
|
|
||||||
virtual Node *Lookup(const char *name, bool traverseLinks);
|
virtual Node* LookupDontTraverse(const char* name);
|
||||||
|
|
||||||
virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize);
|
virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize);
|
||||||
virtual status_t GetNextNode(void *cookie, Node **_node);
|
virtual status_t GetNextNode(void *cookie, Node **_node);
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
SubDir HAIKU_TOP src system boot loader file_systems packagefs ;
|
||||||
|
|
||||||
|
UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ;
|
||||||
|
UsePrivateHeaders kernel shared ;
|
||||||
|
SubDirSysHdrs $(HAIKU_TOP) headers libs zlib ;
|
||||||
|
|
||||||
|
DEFINES += _BOOT_MODE ;
|
||||||
|
|
||||||
|
local kernelC++Header = [ FDirName $(HAIKU_TOP) headers private kernel util
|
||||||
|
kernel_cpp.h ] ;
|
||||||
|
|
||||||
|
SubDirC++Flags -fno-rtti -include $(kernelC++Header) ;
|
||||||
|
|
||||||
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package ] ;
|
||||||
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ;
|
||||||
|
|
||||||
|
|
||||||
|
KernelStaticLibrary boot_packagefs :
|
||||||
|
packagefs.cpp
|
||||||
|
|
||||||
|
# package kit
|
||||||
|
BlockBufferCacheNoLock.cpp
|
||||||
|
|
||||||
|
# package kit/hpkg
|
||||||
|
BlockBufferCache.cpp
|
||||||
|
BlockBufferCacheImpl.cpp
|
||||||
|
BufferCache.cpp
|
||||||
|
CachedBuffer.cpp
|
||||||
|
DataOutput.cpp
|
||||||
|
DataReader.cpp
|
||||||
|
ErrorOutput.cpp
|
||||||
|
FDDataReader.cpp
|
||||||
|
PackageContentHandler.cpp
|
||||||
|
PackageData.cpp
|
||||||
|
PackageDataReader.cpp
|
||||||
|
PackageEntry.cpp
|
||||||
|
PackageEntryAttribute.cpp
|
||||||
|
PackageReaderImpl.cpp
|
||||||
|
ReaderImplBase.cpp
|
||||||
|
|
||||||
|
# compression
|
||||||
|
ZlibCompressionBase.cpp
|
||||||
|
ZlibDecompressor.cpp
|
||||||
|
|
||||||
|
: -fno-pic
|
||||||
|
;
|
||||||
@@ -0,0 +1,807 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "packagefs.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <package/BlockBufferCacheNoLock.h>
|
||||||
|
#include <package/hpkg/DataReader.h>
|
||||||
|
#include <package/hpkg/ErrorOutput.h>
|
||||||
|
#include <package/hpkg/PackageDataReader.h>
|
||||||
|
#include <package/hpkg/PackageEntry.h>
|
||||||
|
#include <package/hpkg/PackageEntryAttribute.h>
|
||||||
|
#include <package/hpkg/PackageReaderImpl.h>
|
||||||
|
|
||||||
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
|
||||||
|
#include <Referenceable.h>
|
||||||
|
|
||||||
|
#include <boot/platform.h>
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
# define RETURN_ERROR(error) return (error);
|
||||||
|
#else
|
||||||
|
# define RETURN_ERROR(err) \
|
||||||
|
{ \
|
||||||
|
status_t _status = err; \
|
||||||
|
if (_status < B_OK) \
|
||||||
|
dprintf("%s:%d: %s\n", __FILE__, __LINE__, strerror(_status)); \
|
||||||
|
return _status; \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
using namespace BPackageKit;
|
||||||
|
using namespace BPackageKit::BHPKG;
|
||||||
|
using BPackageKit::BHPKG::BPrivate::PackageReaderImpl;
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
|
struct PackageDirectory;
|
||||||
|
struct PackageNode;
|
||||||
|
struct PackageVolume;
|
||||||
|
|
||||||
|
|
||||||
|
static status_t create_node(PackageNode* packageNode, ::Node*& _node);
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - PackageNode
|
||||||
|
|
||||||
|
|
||||||
|
struct PackageNode : DoublyLinkedListLinkImpl<PackageNode> {
|
||||||
|
PackageNode(PackageVolume* volume, mode_t mode)
|
||||||
|
:
|
||||||
|
fVolume(volume),
|
||||||
|
fParentDirectory(NULL),
|
||||||
|
fName(NULL),
|
||||||
|
fMode(mode)
|
||||||
|
{
|
||||||
|
fModifiedTime.tv_sec = 0;
|
||||||
|
fModifiedTime.tv_nsec = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~PackageNode()
|
||||||
|
{
|
||||||
|
free(fName);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t Init(PackageDirectory* parentDir, const char* name)
|
||||||
|
{
|
||||||
|
fParentDirectory = parentDir;
|
||||||
|
fName = strdup(name);
|
||||||
|
|
||||||
|
return fName != NULL ? B_OK : B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageVolume* Volume() const
|
||||||
|
{
|
||||||
|
return fVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* Name() const
|
||||||
|
{
|
||||||
|
return fName;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode_t Mode() const
|
||||||
|
{
|
||||||
|
return fMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetModifiedTime(const timespec& time)
|
||||||
|
{
|
||||||
|
fModifiedTime = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
const timespec& ModifiedTime() const
|
||||||
|
{
|
||||||
|
return fModifiedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PackageVolume* fVolume;
|
||||||
|
PackageDirectory* fParentDirectory;
|
||||||
|
char* fName;
|
||||||
|
mode_t fMode;
|
||||||
|
timespec fModifiedTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - PackageFile
|
||||||
|
|
||||||
|
|
||||||
|
struct PackageFile : PackageNode {
|
||||||
|
PackageFile(PackageVolume* volume, mode_t mode, const BPackageData& data)
|
||||||
|
:
|
||||||
|
PackageNode(volume, mode),
|
||||||
|
fData(data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const BPackageData& Data() const
|
||||||
|
{
|
||||||
|
return fData;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t Size() const
|
||||||
|
{
|
||||||
|
return fData.UncompressedSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BPackageData fData;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - PackageSymlink
|
||||||
|
|
||||||
|
|
||||||
|
struct PackageSymlink : PackageNode {
|
||||||
|
PackageSymlink(PackageVolume* volume, mode_t mode)
|
||||||
|
:
|
||||||
|
PackageNode(volume, mode),
|
||||||
|
fPath(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~PackageSymlink()
|
||||||
|
{
|
||||||
|
free(fPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t SetSymlinkPath(const char* path)
|
||||||
|
{
|
||||||
|
fPath = strdup(path);
|
||||||
|
return fPath != NULL ? B_OK : B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* SymlinkPath() const
|
||||||
|
{
|
||||||
|
return fPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char* fPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - PackageDirectory
|
||||||
|
|
||||||
|
|
||||||
|
struct PackageDirectory : PackageNode {
|
||||||
|
PackageDirectory(PackageVolume* volume, mode_t mode)
|
||||||
|
:
|
||||||
|
PackageNode(volume, mode)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddChild(PackageNode* node)
|
||||||
|
{
|
||||||
|
fEntries.Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageNode* FirstChild() const
|
||||||
|
{
|
||||||
|
return fEntries.Head();
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageNode* NextChild(PackageNode* child) const
|
||||||
|
{
|
||||||
|
return fEntries.GetNext(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageNode* Lookup(const char* name) const
|
||||||
|
{
|
||||||
|
for (NodeList::ConstIterator it = fEntries.GetIterator();
|
||||||
|
PackageNode* child = it.Next();) {
|
||||||
|
if (strcmp(child->Name(), name) == 0)
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef DoublyLinkedList<PackageNode> NodeList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
NodeList fEntries;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - FileDataReader
|
||||||
|
|
||||||
|
|
||||||
|
struct FileDataReader {
|
||||||
|
FileDataReader(int fd, const BPackageData& data)
|
||||||
|
:
|
||||||
|
fDataReader(fd),
|
||||||
|
fData(data),
|
||||||
|
fPackageDataReader(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~FileDataReader()
|
||||||
|
{
|
||||||
|
delete fPackageDataReader;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t Init(BPackageDataReaderFactory* dataReaderFactory)
|
||||||
|
{
|
||||||
|
if (fData.IsEncodedInline())
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
return dataReaderFactory->CreatePackageDataReader(&fDataReader,
|
||||||
|
fData, fPackageDataReader);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t ReadData(off_t offset, void* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
if (fData.IsEncodedInline()) {
|
||||||
|
BBufferDataReader dataReader(fData.InlineData(),
|
||||||
|
fData.CompressedSize());
|
||||||
|
return dataReader.ReadData(offset, buffer, bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fPackageDataReader->ReadData(offset, buffer, bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BFDDataReader fDataReader;
|
||||||
|
BPackageData fData;
|
||||||
|
BPackageDataReader* fPackageDataReader;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - PackageVolume
|
||||||
|
|
||||||
|
|
||||||
|
struct PackageVolume : BReferenceable {
|
||||||
|
PackageVolume()
|
||||||
|
:
|
||||||
|
fRootDirectory(this, S_IFDIR),
|
||||||
|
fBufferCache(B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB, 2),
|
||||||
|
fDataReaderFactory(&fBufferCache),
|
||||||
|
fFD(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~PackageVolume()
|
||||||
|
{
|
||||||
|
if (fFD >= 0)
|
||||||
|
close(fFD);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t Init(int fd)
|
||||||
|
{
|
||||||
|
status_t error = fBufferCache.Init();
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
fFD = dup(fd);
|
||||||
|
if (fFD < 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageDirectory* RootDirectory()
|
||||||
|
{
|
||||||
|
return &fRootDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddNode(PackageNode* node)
|
||||||
|
{
|
||||||
|
fRootDirectory.AddChild(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t CreateFileDataReader(const BPackageData& data,
|
||||||
|
FileDataReader*& _fileDataReader)
|
||||||
|
{
|
||||||
|
// create the file reader object
|
||||||
|
FileDataReader* fileDataReader = new(std::nothrow) FileDataReader(fFD,
|
||||||
|
data);
|
||||||
|
if (fileDataReader == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
ObjectDeleter<FileDataReader> fileDataReaderDeleter(fileDataReader);
|
||||||
|
|
||||||
|
status_t error = fileDataReader->Init(&fDataReaderFactory);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
_fileDataReader = fileDataReaderDeleter.Detach();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PackageDirectory fRootDirectory;
|
||||||
|
BBlockBufferCacheNoLock fBufferCache;
|
||||||
|
BPackageDataReaderFactory fDataReaderFactory;
|
||||||
|
int fFD;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - PackageLoaderErrorOutput
|
||||||
|
|
||||||
|
|
||||||
|
struct PackageLoaderErrorOutput : BErrorOutput {
|
||||||
|
PackageLoaderErrorOutput()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void PrintErrorVarArgs(const char* format, va_list args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - PackageLoaderContentHandler
|
||||||
|
|
||||||
|
|
||||||
|
struct PackageLoaderContentHandler : BPackageContentHandler {
|
||||||
|
PackageLoaderContentHandler(PackageVolume* volume)
|
||||||
|
:
|
||||||
|
fVolume(volume),
|
||||||
|
fErrorOccurred(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t Init()
|
||||||
|
{
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t HandleEntry(BPackageEntry* entry)
|
||||||
|
{
|
||||||
|
if (fErrorOccurred)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
PackageDirectory* parentDir = NULL;
|
||||||
|
if (const BPackageEntry* parentEntry = entry->Parent()) {
|
||||||
|
if (!S_ISDIR(parentEntry->Mode()))
|
||||||
|
RETURN_ERROR(B_BAD_DATA);
|
||||||
|
|
||||||
|
parentDir = static_cast<PackageDirectory*>(
|
||||||
|
(PackageNode*)parentEntry->UserToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t error;
|
||||||
|
|
||||||
|
// get the file mode -- filter out write permissions
|
||||||
|
mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH);
|
||||||
|
|
||||||
|
// create the package node
|
||||||
|
PackageNode* node;
|
||||||
|
if (S_ISREG(mode)) {
|
||||||
|
// file
|
||||||
|
node = new(std::nothrow) PackageFile(fVolume, mode, entry->Data());
|
||||||
|
} else if (S_ISLNK(mode)) {
|
||||||
|
// symlink
|
||||||
|
PackageSymlink* symlink = new(std::nothrow) PackageSymlink(
|
||||||
|
fVolume, mode);
|
||||||
|
if (symlink == NULL)
|
||||||
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
|
|
||||||
|
error = symlink->SetSymlinkPath(entry->SymlinkPath());
|
||||||
|
if (error != B_OK) {
|
||||||
|
delete symlink;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = symlink;
|
||||||
|
} else if (S_ISDIR(mode)) {
|
||||||
|
// directory
|
||||||
|
node = new(std::nothrow) PackageDirectory(fVolume, mode);
|
||||||
|
} else
|
||||||
|
RETURN_ERROR(B_BAD_DATA);
|
||||||
|
|
||||||
|
if (node == NULL)
|
||||||
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
|
|
||||||
|
error = node->Init(parentDir, entry->Name());
|
||||||
|
if (error != B_OK) {
|
||||||
|
delete node;
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->SetModifiedTime(entry->ModifiedTime());
|
||||||
|
|
||||||
|
// add it to the parent directory
|
||||||
|
if (parentDir != NULL)
|
||||||
|
parentDir->AddChild(node);
|
||||||
|
else
|
||||||
|
fVolume->AddNode(node);
|
||||||
|
|
||||||
|
entry->SetUserToken(node);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t HandleEntryAttribute(BPackageEntry* entry,
|
||||||
|
BPackageEntryAttribute* attribute)
|
||||||
|
{
|
||||||
|
// attributes aren't needed in the boot loader
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t HandleEntryDone(BPackageEntry* entry)
|
||||||
|
{
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t HandlePackageAttribute(
|
||||||
|
const BPackageInfoAttributeValue& value)
|
||||||
|
{
|
||||||
|
// TODO?
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void HandleErrorOccurred()
|
||||||
|
{
|
||||||
|
fErrorOccurred = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PackageVolume* fVolume;
|
||||||
|
bool fErrorOccurred;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - File
|
||||||
|
|
||||||
|
|
||||||
|
struct File : ::Node {
|
||||||
|
File(PackageFile* file)
|
||||||
|
:
|
||||||
|
fFile(file)
|
||||||
|
{
|
||||||
|
fFile->Volume()->AcquireReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
~File()
|
||||||
|
{
|
||||||
|
fFile->Volume()->ReleaseReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer,
|
||||||
|
size_t bufferSize)
|
||||||
|
{
|
||||||
|
off_t size = fFile->Size();
|
||||||
|
if (pos < 0 || pos > size)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (pos + bufferSize > size)
|
||||||
|
bufferSize = size - pos;
|
||||||
|
|
||||||
|
if (bufferSize > 0) {
|
||||||
|
FileDataReader* dataReader = (FileDataReader*)cookie;
|
||||||
|
status_t error = dataReader->ReadData(pos, buffer, bufferSize);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ssize_t WriteAt(void* cookie, off_t pos, const void *buffer,
|
||||||
|
size_t bufferSize)
|
||||||
|
{
|
||||||
|
return B_READ_ONLY_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t GetName(char* nameBuffer, size_t bufferSize) const
|
||||||
|
{
|
||||||
|
strlcpy(nameBuffer, fFile->Name(), bufferSize);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t Open(void** _cookie, int mode)
|
||||||
|
{
|
||||||
|
if ((mode & O_ACCMODE) != O_RDONLY && (mode & O_ACCMODE) != O_RDWR)
|
||||||
|
return B_NOT_ALLOWED;
|
||||||
|
|
||||||
|
FileDataReader* dataReader;
|
||||||
|
status_t error = fFile->Volume()->CreateFileDataReader(fFile->Data(),
|
||||||
|
dataReader);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
*_cookie = dataReader;
|
||||||
|
Acquire();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t Close(void* cookie)
|
||||||
|
{
|
||||||
|
FileDataReader* dataReader = (FileDataReader*)cookie;
|
||||||
|
delete dataReader;
|
||||||
|
Release();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual int32 Type() const
|
||||||
|
{
|
||||||
|
return fFile->Mode() & S_IFMT;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual off_t Size() const
|
||||||
|
{
|
||||||
|
return fFile->Size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PackageFile* fFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Symlink
|
||||||
|
|
||||||
|
|
||||||
|
struct Symlink : ::Node {
|
||||||
|
Symlink(PackageSymlink* symlink)
|
||||||
|
:
|
||||||
|
fSymlink(symlink)
|
||||||
|
{
|
||||||
|
fSymlink->Volume()->AcquireReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Symlink()
|
||||||
|
{
|
||||||
|
fSymlink->Volume()->ReleaseReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer,
|
||||||
|
size_t bufferSize)
|
||||||
|
{
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ssize_t WriteAt(void* cookie, off_t pos, const void *buffer,
|
||||||
|
size_t bufferSize)
|
||||||
|
{
|
||||||
|
return B_READ_ONLY_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t ReadLink(char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
const char* path = fSymlink->SymlinkPath();
|
||||||
|
size_t size = strlen(path) + 1;
|
||||||
|
|
||||||
|
if (size > bufferSize)
|
||||||
|
return B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
memcpy(buffer, path, size);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t GetName(char* nameBuffer, size_t bufferSize) const
|
||||||
|
{
|
||||||
|
strlcpy(nameBuffer, fSymlink->Name(), bufferSize);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int32 Type() const
|
||||||
|
{
|
||||||
|
return fSymlink->Mode() & S_IFMT;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual off_t Size() const
|
||||||
|
{
|
||||||
|
return strlen(fSymlink->SymlinkPath()) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PackageSymlink* fSymlink;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Directory
|
||||||
|
|
||||||
|
|
||||||
|
struct Directory : ::Directory {
|
||||||
|
Directory(PackageDirectory* symlink)
|
||||||
|
:
|
||||||
|
fDirectory(symlink)
|
||||||
|
{
|
||||||
|
fDirectory->Volume()->AcquireReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Directory()
|
||||||
|
{
|
||||||
|
fDirectory->Volume()->ReleaseReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer,
|
||||||
|
size_t bufferSize)
|
||||||
|
{
|
||||||
|
return B_IS_A_DIRECTORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ssize_t WriteAt(void* cookie, off_t pos, const void *buffer,
|
||||||
|
size_t bufferSize)
|
||||||
|
{
|
||||||
|
return B_IS_A_DIRECTORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t GetName(char* nameBuffer, size_t bufferSize) const
|
||||||
|
{
|
||||||
|
strlcpy(nameBuffer, fDirectory->Name(), bufferSize);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int32 Type() const
|
||||||
|
{
|
||||||
|
return fDirectory->Mode() & S_IFMT;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t Open(void** _cookie, int mode)
|
||||||
|
{
|
||||||
|
if ((mode & O_ACCMODE) != O_RDONLY && (mode & O_ACCMODE) != O_RDWR)
|
||||||
|
return B_NOT_ALLOWED;
|
||||||
|
|
||||||
|
Cookie* cookie = new(std::nothrow) Cookie;
|
||||||
|
if (cookie == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
cookie->nextChild = fDirectory->FirstChild();
|
||||||
|
|
||||||
|
Acquire();
|
||||||
|
*_cookie = cookie;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t Close(void* _cookie)
|
||||||
|
{
|
||||||
|
Cookie* cookie = (Cookie*)_cookie;
|
||||||
|
delete cookie;
|
||||||
|
Release();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Node* LookupDontTraverse(const char* name)
|
||||||
|
{
|
||||||
|
// look up the child
|
||||||
|
PackageNode* child = fDirectory->Lookup(name);
|
||||||
|
if (child == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// create the node
|
||||||
|
::Node* node;
|
||||||
|
return create_node(child, node) == B_OK ? node : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t GetNextEntry(void* _cookie, char* nameBuffer,
|
||||||
|
size_t bufferSize)
|
||||||
|
{
|
||||||
|
Cookie* cookie = (Cookie*)_cookie;
|
||||||
|
PackageNode* child = cookie->nextChild;
|
||||||
|
if (child == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
cookie->nextChild = fDirectory->NextChild(child);
|
||||||
|
|
||||||
|
strlcpy(nameBuffer, child->Name(), bufferSize);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t GetNextNode(void* _cookie, Node** _node)
|
||||||
|
{
|
||||||
|
Cookie* cookie = (Cookie*)_cookie;
|
||||||
|
PackageNode* child = cookie->nextChild;
|
||||||
|
if (child == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
cookie->nextChild = fDirectory->NextChild(child);
|
||||||
|
|
||||||
|
return create_node(child, *_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t Rewind(void* _cookie)
|
||||||
|
{
|
||||||
|
Cookie* cookie = (Cookie*)_cookie;
|
||||||
|
cookie->nextChild = NULL;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool IsEmpty()
|
||||||
|
{
|
||||||
|
return fDirectory->FirstChild() == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Cookie {
|
||||||
|
PackageNode* nextChild;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
PackageDirectory* fDirectory;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
create_node(PackageNode* packageNode, ::Node*& _node)
|
||||||
|
{
|
||||||
|
if (packageNode == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
::Node* node;
|
||||||
|
switch (packageNode->Mode() & S_IFMT) {
|
||||||
|
case S_IFREG:
|
||||||
|
node = new(std::nothrow) File(
|
||||||
|
static_cast<PackageFile*>(packageNode));
|
||||||
|
break;
|
||||||
|
case S_IFLNK:
|
||||||
|
node = new(std::nothrow) Symlink(
|
||||||
|
static_cast<PackageSymlink*>(packageNode));
|
||||||
|
break;
|
||||||
|
case S_IFDIR:
|
||||||
|
node = new(std::nothrow) Directory(
|
||||||
|
static_cast<PackageDirectory*>(packageNode));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
_node = node;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
packagefs_mount_file(int fd, ::Directory*& _mountedDirectory)
|
||||||
|
{
|
||||||
|
PackageLoaderErrorOutput errorOutput;
|
||||||
|
PackageReaderImpl packageReader(&errorOutput);
|
||||||
|
status_t error = packageReader.Init(fd, false);
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
// create the volume
|
||||||
|
PackageVolume* volume = new(std::nothrow) PackageVolume;
|
||||||
|
if (volume == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
BReference<PackageVolume> volumeReference(volume, true);
|
||||||
|
|
||||||
|
error = volume->Init(fd);
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
// parse content -- this constructs the entry/node tree
|
||||||
|
PackageLoaderContentHandler handler(volume);
|
||||||
|
error = handler.Init();
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
error = packageReader.ParseContent(&handler);
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
// create a VFS node for the root node
|
||||||
|
::Node* rootNode;
|
||||||
|
error = create_node(volume->RootDirectory(), rootNode);
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
_mountedDirectory = static_cast< ::Directory*>(rootNode);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef BOOT_LOADER_FILE_SYSTEMS_PACKAGEFS_H
|
||||||
|
#define BOOT_LOADER_FILE_SYSTEMS_PACKAGEFS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
|
||||||
|
class Directory;
|
||||||
|
class Node;
|
||||||
|
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
|
||||||
|
status_t packagefs_mount_file(int fd, Directory*& _mountedDirectory);
|
||||||
|
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BOOT_LOADER_FILE_SYSTEMS_PACKAGEFS_H
|
||||||
@@ -119,7 +119,7 @@ public:
|
|||||||
size_t bufferSize) const;
|
size_t bufferSize) const;
|
||||||
|
|
||||||
virtual TarFS::Entry* LookupEntry(const char* name);
|
virtual TarFS::Entry* LookupEntry(const char* name);
|
||||||
virtual ::Node* Lookup(const char* name, bool traverseLinks);
|
virtual ::Node* LookupDontTraverse(const char* name);
|
||||||
|
|
||||||
virtual status_t GetNextEntry(void* cookie, char* nameBuffer,
|
virtual status_t GetNextEntry(void* cookie, char* nameBuffer,
|
||||||
size_t bufferSize);
|
size_t bufferSize);
|
||||||
@@ -153,6 +153,8 @@ public:
|
|||||||
virtual ssize_t WriteAt(void* cookie, off_t pos,
|
virtual ssize_t WriteAt(void* cookie, off_t pos,
|
||||||
const void* buffer, size_t bufferSize);
|
const void* buffer, size_t bufferSize);
|
||||||
|
|
||||||
|
virtual status_t ReadLink(char* buffer, size_t bufferSize);
|
||||||
|
|
||||||
virtual status_t GetName(char* nameBuffer,
|
virtual status_t GetName(char* nameBuffer,
|
||||||
size_t bufferSize) const;
|
size_t bufferSize) const;
|
||||||
|
|
||||||
@@ -392,25 +394,13 @@ TarFS::Directory::LookupEntry(const char* name)
|
|||||||
|
|
||||||
|
|
||||||
::Node*
|
::Node*
|
||||||
TarFS::Directory::Lookup(const char* name, bool traverseLinks)
|
TarFS::Directory::LookupDontTraverse(const char* name)
|
||||||
{
|
{
|
||||||
TarFS::Entry* entry = LookupEntry(name);
|
TarFS::Entry* entry = LookupEntry(name);
|
||||||
if (!entry)
|
if (!entry)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
Node* node = entry->ToNode();
|
Node* node = entry->ToNode();
|
||||||
|
|
||||||
if (traverseLinks) {
|
|
||||||
if (S_ISLNK(node->Type())) {
|
|
||||||
Symlink* symlink = static_cast<Symlink*>(node);
|
|
||||||
int fd = open_from(this, symlink->LinkPath(), O_RDONLY);
|
|
||||||
if (fd >= 0) {
|
|
||||||
node = get_node_from(fd);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node)
|
if (node)
|
||||||
node->Acquire();
|
node->Acquire();
|
||||||
|
|
||||||
@@ -587,6 +577,20 @@ TarFS::Symlink::WriteAt(void* cookie, off_t pos, const void* buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
TarFS::Symlink::ReadLink(char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
const char* path = fHeader->linkname;
|
||||||
|
size_t size = strlen(path) + 1;
|
||||||
|
|
||||||
|
if (size > bufferSize)
|
||||||
|
return B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
memcpy(buffer, path, size);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
TarFS::Symlink::GetName(char* nameBuffer, size_t bufferSize) const
|
TarFS::Symlink::GetName(char* nameBuffer, size_t bufferSize) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <syscall_utils.h>
|
#include <syscall_utils.h>
|
||||||
|
|
||||||
#include "RootFileSystem.h"
|
#include "RootFileSystem.h"
|
||||||
|
#include "file_systems/packagefs/packagefs.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace boot;
|
using namespace boot;
|
||||||
@@ -98,6 +99,13 @@ Node::Close(void *cookie)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Node::ReadLink(char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Node::GetName(char *nameBuffer, size_t bufferSize) const
|
Node::GetName(char *nameBuffer, size_t bufferSize) const
|
||||||
{
|
{
|
||||||
@@ -209,6 +217,40 @@ Directory::Type() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Node*
|
||||||
|
Directory::Lookup(const char* name, bool traverseLinks)
|
||||||
|
{
|
||||||
|
Node* node = LookupDontTraverse(name);
|
||||||
|
if (node == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!traverseLinks || !S_ISLNK(node->Type()))
|
||||||
|
return node;
|
||||||
|
|
||||||
|
// the node is a symbolic link, so we have to resolve the path
|
||||||
|
char linkPath[B_PATH_NAME_LENGTH];
|
||||||
|
status_t error = node->ReadLink(linkPath, sizeof(linkPath));
|
||||||
|
|
||||||
|
node->Release();
|
||||||
|
// we don't need this one anymore
|
||||||
|
|
||||||
|
if (error != B_OK)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// let open_from() do the real work
|
||||||
|
int fd = open_from(this, linkPath, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
node = get_node_from(fd);
|
||||||
|
if (node != NULL)
|
||||||
|
node->Acquire();
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Directory::CreateFile(const char *name, mode_t permissions, Node **_node)
|
Directory::CreateFile(const char *name, mode_t permissions, Node **_node)
|
||||||
{
|
{
|
||||||
@@ -393,7 +435,7 @@ BootVolume::SetTo(Directory* rootDirectory)
|
|||||||
|
|
||||||
fSystemDirectory = static_cast<Directory*>(systemNode);
|
fSystemDirectory = static_cast<Directory*>(systemNode);
|
||||||
|
|
||||||
// check, if the system is packaged
|
// try opening the system package
|
||||||
int packageFD = open_from(fSystemDirectory, "packages/haiku.hpkg",
|
int packageFD = open_from(fSystemDirectory, "packages/haiku.hpkg",
|
||||||
O_RDONLY);
|
O_RDONLY);
|
||||||
fPackaged = packageFD >= 0;
|
fPackaged = packageFD >= 0;
|
||||||
@@ -401,10 +443,18 @@ BootVolume::SetTo(Directory* rootDirectory)
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
// the system is packaged -- mount the packagefs
|
// the system is packaged -- mount the packagefs
|
||||||
// TODO:...
|
Directory* packageRootDirectory;
|
||||||
Unset();
|
status_t error = packagefs_mount_file(packageFD, packageRootDirectory);
|
||||||
dprintf("BootVolume::SetTo(): packagefs not supported yet!\n");
|
close(packageFD);
|
||||||
return B_NOT_SUPPORTED;
|
if (error != B_OK) {
|
||||||
|
Unset();
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
fSystemDirectory->Release();
|
||||||
|
fSystemDirectory = packageRootDirectory;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -725,6 +775,13 @@ read_pos(int fd, off_t offset, void *buffer, size_t bufferSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
pread(int fd, void* buffer, size_t bufferSize, off_t offset)
|
||||||
|
{
|
||||||
|
return read_pos(fd, offset, buffer, bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
read(int fd, void *buffer, size_t bufferSize)
|
read(int fd, void *buffer, size_t bufferSize)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user