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 Close(void *cookie);
|
||||
|
||||
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) = 0;
|
||||
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) = 0;
|
||||
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer,
|
||||
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 GetFileMap(struct file_map_run *runs, int32 *count);
|
||||
@@ -55,7 +59,8 @@ class Directory : public Node {
|
||||
|
||||
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 GetNextNode(void *cookie, Node **_node) = 0;
|
||||
|
||||
@@ -29,7 +29,7 @@ RootFileSystem::~RootFileSystem()
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
RootFileSystem::Open(void **_cookie, int mode)
|
||||
{
|
||||
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)
|
||||
{
|
||||
delete (EntryIterator *)cookie;
|
||||
@@ -50,8 +50,8 @@ RootFileSystem::Close(void *cookie)
|
||||
}
|
||||
|
||||
|
||||
Node *
|
||||
RootFileSystem::Lookup(const char *name, bool /*traverseLinks*/)
|
||||
Node*
|
||||
RootFileSystem::LookupDontTraverse(const char* name)
|
||||
{
|
||||
EntryIterator iterator = fLinks.GetIterator();
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
EntryIterator *iterator = (EntryIterator *)_cookie;
|
||||
@@ -113,24 +113,24 @@ RootFileSystem::GetNextNode(void *_cookie, Node **_node)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
RootFileSystem::Rewind(void *_cookie)
|
||||
{
|
||||
EntryIterator *iterator = (EntryIterator *)_cookie;
|
||||
|
||||
iterator->Rewind();
|
||||
return B_OK;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
bool
|
||||
RootFileSystem::IsEmpty()
|
||||
{
|
||||
return fList.IsEmpty();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
RootFileSystem::AddVolume(Directory *volume, Partition *partition)
|
||||
{
|
||||
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)
|
||||
{
|
||||
EntryIterator iterator = fList.GetIterator();
|
||||
|
||||
@@ -20,7 +20,7 @@ class RootFileSystem : public Directory {
|
||||
virtual status_t Open(void **_cookie, int mode);
|
||||
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 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 fat ;
|
||||
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 ;
|
||||
|
||||
@@ -45,14 +45,14 @@ Directory::~Directory()
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
Directory::InitCheck()
|
||||
{
|
||||
return fNode.ValidateCheckSum();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
Directory::Open(void **_cookie, int mode)
|
||||
{
|
||||
_inherited::Open(_cookie, mode);
|
||||
@@ -71,7 +71,7 @@ Directory::Open(void **_cookie, int mode)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
Directory::Close(void *cookie)
|
||||
{
|
||||
_inherited::Close(cookie);
|
||||
@@ -81,8 +81,8 @@ Directory::Close(void *cookie)
|
||||
}
|
||||
|
||||
|
||||
Node *
|
||||
Directory::Lookup(const char *name, bool traverseLinks)
|
||||
Node*
|
||||
Directory::LookupDontTraverse(const char* name)
|
||||
{
|
||||
if (!strcmp(name, ".")) {
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return B_ERROR;
|
||||
|
||||
@@ -27,7 +27,7 @@ class Directory : public ::Directory {
|
||||
virtual status_t Open(void **_cookie, int mode);
|
||||
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 GetNextNode(void *cookie, Node **_node);
|
||||
|
||||
@@ -52,14 +52,14 @@ Directory::~Directory()
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
Directory::InitCheck()
|
||||
{
|
||||
return fStream.InitCheck();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
Directory::Open(void **_cookie, int mode)
|
||||
{
|
||||
_inherited::Open(_cookie, mode);
|
||||
@@ -72,7 +72,7 @@ Directory::Open(void **_cookie, int mode)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
Directory::Close(void *cookie)
|
||||
{
|
||||
_inherited::Close(cookie);
|
||||
@@ -82,43 +82,18 @@ Directory::Close(void *cookie)
|
||||
}
|
||||
|
||||
|
||||
Node *
|
||||
Directory::Lookup(const char *name, bool traverseLinks)
|
||||
Node*
|
||||
Directory::LookupDontTraverse(const char* name)
|
||||
{
|
||||
off_t id;
|
||||
if (fTree.Find((uint8 *)name, strlen(name), &id) < B_OK)
|
||||
return NULL;
|
||||
|
||||
Node *node = 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;
|
||||
return Stream::NodeFactory(fStream.GetVolume(), id);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
Directory::GetNextEntry(void *cookie, char *name, size_t size)
|
||||
{
|
||||
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)
|
||||
{
|
||||
TreeIterator *iterator = (TreeIterator *)cookie;
|
||||
@@ -149,7 +124,7 @@ Directory::GetNextNode(void *cookie, Node **_node)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
Directory::Rewind(void *cookie)
|
||||
{
|
||||
TreeIterator *iterator = (TreeIterator *)cookie;
|
||||
@@ -158,7 +133,7 @@ Directory::Rewind(void *cookie)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
bool
|
||||
Directory::IsEmpty()
|
||||
{
|
||||
TreeIterator iterator(&fTree);
|
||||
|
||||
@@ -27,7 +27,7 @@ class Directory : public ::Directory {
|
||||
virtual status_t Open(void **_cookie, int mode);
|
||||
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 GetNextNode(void *cookie, Node **_node);
|
||||
|
||||
@@ -20,7 +20,8 @@ class Link : public File {
|
||||
Link(const Stream &stream);
|
||||
|
||||
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 WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
|
||||
|
||||
@@ -351,10 +351,10 @@ Directory::Close(void *cookie)
|
||||
}
|
||||
|
||||
|
||||
Node *
|
||||
Directory::Lookup(const char *name, bool traverseLinks)
|
||||
Node*
|
||||
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, ".")) {
|
||||
Acquire();
|
||||
return this;
|
||||
|
||||
@@ -31,7 +31,7 @@ class Directory : public ::Directory {
|
||||
virtual status_t Open(void **_cookie, int mode);
|
||||
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 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;
|
||||
|
||||
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,
|
||||
size_t bufferSize);
|
||||
@@ -153,6 +153,8 @@ public:
|
||||
virtual ssize_t WriteAt(void* cookie, off_t pos,
|
||||
const void* buffer, size_t bufferSize);
|
||||
|
||||
virtual status_t ReadLink(char* buffer, size_t bufferSize);
|
||||
|
||||
virtual status_t GetName(char* nameBuffer,
|
||||
size_t bufferSize) const;
|
||||
|
||||
@@ -392,25 +394,13 @@ TarFS::Directory::LookupEntry(const char* name)
|
||||
|
||||
|
||||
::Node*
|
||||
TarFS::Directory::Lookup(const char* name, bool traverseLinks)
|
||||
TarFS::Directory::LookupDontTraverse(const char* name)
|
||||
{
|
||||
TarFS::Entry* entry = LookupEntry(name);
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
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)
|
||||
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
|
||||
TarFS::Symlink::GetName(char* nameBuffer, size_t bufferSize) const
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <syscall_utils.h>
|
||||
|
||||
#include "RootFileSystem.h"
|
||||
#include "file_systems/packagefs/packagefs.h"
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
Directory::CreateFile(const char *name, mode_t permissions, Node **_node)
|
||||
{
|
||||
@@ -393,7 +435,7 @@ BootVolume::SetTo(Directory* rootDirectory)
|
||||
|
||||
fSystemDirectory = static_cast<Directory*>(systemNode);
|
||||
|
||||
// check, if the system is packaged
|
||||
// try opening the system package
|
||||
int packageFD = open_from(fSystemDirectory, "packages/haiku.hpkg",
|
||||
O_RDONLY);
|
||||
fPackaged = packageFD >= 0;
|
||||
@@ -401,10 +443,18 @@ BootVolume::SetTo(Directory* rootDirectory)
|
||||
return B_OK;
|
||||
|
||||
// the system is packaged -- mount the packagefs
|
||||
// TODO:...
|
||||
Unset();
|
||||
dprintf("BootVolume::SetTo(): packagefs not supported yet!\n");
|
||||
return B_NOT_SUPPORTED;
|
||||
Directory* packageRootDirectory;
|
||||
status_t error = packagefs_mount_file(packageFD, packageRootDirectory);
|
||||
close(packageFD);
|
||||
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
|
||||
read(int fd, void *buffer, size_t bufferSize)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user