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:
Ingo Weinhold
2011-07-17 16:54:15 +02:00
parent 3057223796
commit cbc85916fb
16 changed files with 1006 additions and 83 deletions
+8 -3
View File
@@ -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;
+11 -11
View File
@@ -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();
+1 -1
View File
@@ -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
{
+62 -5
View File
@@ -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)
{