Work in progress:

* The FS parses package files from "/boot/common/packages" and builds an
  node tree representation of the contained entries. Merging directories should
  work. Lots of other stuff is missing yet, though.
* Implemented the hooks for directory entry lookup and iteration. So it's
  possible to see the contents of the FS at least.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34088 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-11-17 11:46:19 +00:00
parent 82df777b3d
commit cc32c48494
25 changed files with 1929 additions and 43 deletions

View File

@ -6,13 +6,93 @@
#include "Directory.h"
#include "DebugSupport.h"
#include "PackageDirectory.h"
Directory::Directory(ino_t id)
:
Node(id)
{
fMode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
}
Directory::~Directory()
{
Node* child = fChildTable.Clear(true);
while (child != NULL) {
Node* next = child->NameHashTableNext();
child->ReleaseReference();
child = next;
}
}
status_t
Directory::Init(Directory* parent, const char* name)
{
status_t error = fChildTable.Init();
if (error != B_OK)
return error;
return Node::Init(parent, name);
}
status_t
Directory::AddPackageNode(PackageNode* packageNode)
{
if (!S_ISDIR(packageNode->Mode()))
return B_BAD_VALUE;
// TODO:...
return B_OK;
}
void
Directory::AddChild(Node* node)
{
fChildTable.Insert(node);
fChildList.Add(node);
}
void
Directory::RemoveChild(Node* node)
{
Node* nextNode = fChildList.GetNext(node);
fChildTable.Remove(node);
fChildList.Remove(node);
// adjust directory iterators pointing to the removed child
for (DirectoryIteratorList::Iterator it = fIterators.GetIterator();
DirectoryIterator* iterator = it.Next();) {
if (iterator->node == node)
iterator->node = nextNode;
}
}
Node*
Directory::FindChild(const char* name)
{
return fChildTable.Lookup(name);
}
void
Directory::AddDirectoryIterator(DirectoryIterator* iterator)
{
fIterators.Add(iterator);
}
void
Directory::RemoveDirectoryIterator(DirectoryIterator* iterator)
{
fIterators.Remove(iterator);
}

View File

@ -9,11 +9,60 @@
#include "Node.h"
struct DirectoryIterator : DoublyLinkedListLinkImpl<DirectoryIterator> {
Node* node;
DirectoryIterator()
:
node(NULL)
{
}
};
typedef DoublyLinkedList<DirectoryIterator> DirectoryIteratorList;
class Directory : public Node {
public:
Directory(ino_t id);
virtual ~Directory();
virtual status_t Init(Directory* parent, const char* name);
virtual status_t AddPackageNode(PackageNode* packageNode);
void AddChild(Node* node);
void RemoveChild(Node* node);
Node* FindChild(const char* name);
inline Node* FirstChild() const;
inline Node* NextChild(Node* node) const;
void AddDirectoryIterator(
DirectoryIterator* iterator);
void RemoveDirectoryIterator(
DirectoryIterator* iterator);
private:
NodeNameHashTable fChildTable;
NodeList fChildList;
DirectoryIteratorList fIterators;
};
Node*
Directory::FirstChild() const
{
return fChildList.First();
}
Node*
Directory::NextChild(Node* node) const
{
return fChildList.GetNext(node);
}
#endif // DIRECTORY_H

View File

@ -0,0 +1,41 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "File.h"
#include "PackageFile.h"
File::File(ino_t id)
:
Node(id)
{
fMode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
}
File::~File()
{
}
status_t
File::Init(Directory* parent, const char* name)
{
return Node::Init(parent, name);
}
status_t
File::AddPackageNode(PackageNode* packageNode)
{
if (!S_ISREG(packageNode->Mode()))
return B_BAD_VALUE;
// TODO:...
return B_OK;
}

View File

@ -0,0 +1,23 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef FILE_H
#define FILE_H
#include "Node.h"
class File : public Node {
public:
File(ino_t id);
virtual ~File();
virtual status_t Init(Directory* parent, const char* name);
virtual status_t AddPackageNode(PackageNode* packageNode);
};
#endif // FILE_H

View File

@ -1,21 +1,56 @@
SubDir HAIKU_TOP src add-ons kernel file_systems packagefs ;
UsePrivateHeaders shared ;
UseLibraryHeaders zlib ;
UsePrivateKernelHeaders ;
UsePrivateHeaders haiku_package shared ;
DEFINES += B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT ;
# TODO: Remove when it is complete!
HAIKU_PACKAGE_FS_SOURCES =
DebugSupport.cpp
Directory.cpp
File.cpp
kernel_interface.cpp
Node.cpp
Package.cpp
PackageDirectory.cpp
PackageDomain.cpp
PackageFile.cpp
PackageNode.cpp
PackageSymlink.cpp
Symlink.cpp
Volume.cpp
;
HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES =
DataOutput.cpp
DataReader.cpp
ErrorOutput.cpp
PackageEntryAttribute.cpp
PackageData.cpp
PackageDataReader.cpp
PackageEntry.cpp
PackageReader.cpp
# compression
ZlibCompressionBase.cpp
ZlibDecompressor.cpp
;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src bin package ] ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src bin package compression ] ;
KernelAddon packagefs
: $(HAIKU_PACKAGE_FS_SOURCES)
: $(HAIKU_STATIC_LIBSUPC++)
:
$(HAIKU_PACKAGE_FS_SOURCES)
$(HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES)
: $(HAIKU_STATIC_LIBSUPC++) libz.a
;

View File

@ -6,14 +6,39 @@
#include "Node.h"
#include <stdlib.h>
#include <string.h>
#include "DebugSupport.h"
Node::Node(ino_t id)
:
fID(id)
fID(id),
fParent(NULL),
fName(NULL),
fUserID(0),
fGroupID(0)
{
rw_lock_init(&fLock, "packagefs node");
}
Node::~Node()
{
PRINT("%p->Node::~Node()\n", this);
free(fName);
rw_lock_destroy(&fLock);
}
status_t
Node::Init(Directory* parent, const char* name)
{
fParent = parent;
fName = strdup(name);
if (fName == NULL)
RETURN_ERROR(B_NO_MEMORY);
return B_OK;
}

View File

@ -8,17 +8,145 @@
#include <fs_interface.h>
#include <AutoLocker.h>
#include <Referenceable.h>
class Node {
#include <lock.h>
#include <util/DoublyLinkedList.h>
#include <util/khash.h>
#include <util/OpenHashTable.h>
class Directory;
class PackageNode;
class Node : public BReferenceable, public DoublyLinkedListLinkImpl<Node> {
public:
Node(ino_t id);
virtual ~Node();
ino_t ID() const { return fID; }
inline bool ReadLock();
inline void ReadUnlock();
inline bool WriteLock();
inline void WriteUnlock();
private:
ino_t ID() const { return fID; }
Directory* Parent() const { return fParent; }
const char* Name() const { return fName; }
Node*& NameHashTableNext()
{ return fNameHashTableNext; }
Node*& IDHashTableNext()
{ return fIDHashTableNext; }
mode_t Mode() const { return fMode; }
uid_t UserID() const { return fUserID; }
gid_t GroupID() const { return fGroupID; }
virtual status_t Init(Directory* parent, const char* name);
virtual status_t AddPackageNode(PackageNode* packageNode) = 0;
protected:
rw_lock fLock;
ino_t fID;
Directory* fParent;
char* fName;
Node* fNameHashTableNext;
Node* fIDHashTableNext;
mode_t fMode;
uid_t fUserID;
gid_t fGroupID;
};
bool
Node::ReadLock()
{
return rw_lock_read_lock(&fLock) == B_OK;
}
void
Node::ReadUnlock()
{
rw_lock_read_unlock(&fLock);
}
bool
Node::WriteLock()
{
return rw_lock_write_lock(&fLock) == B_OK;
}
void
Node::WriteUnlock()
{
rw_lock_write_unlock(&fLock);
}
struct NodeNameHashDefinition {
typedef const char* KeyType;
typedef Node ValueType;
size_t HashKey(const char* key) const
{
return hash_hash_string(key);
}
size_t Hash(const Node* value) const
{
return HashKey(value->Name());
}
bool Compare(const char* key, const Node* value) const
{
return strcmp(value->Name(), key) == 0;
}
Node*& GetLink(Node* value) const
{
return value->NameHashTableNext();
}
};
struct NodeIDHashDefinition {
typedef ino_t KeyType;
typedef Node ValueType;
size_t HashKey(ino_t key) const
{
return (uint64)(key >> 32) ^ (uint32)key;
}
size_t Hash(const Node* value) const
{
return HashKey(value->ID());
}
bool Compare(ino_t key, const Node* value) const
{
return value->ID() == key;
}
Node*& GetLink(Node* value) const
{
return value->IDHashTableNext();
}
};
typedef DoublyLinkedList<Node> NodeList;
typedef BOpenHashTable<NodeNameHashDefinition> NodeNameHashTable;
typedef BOpenHashTable<NodeIDHashDefinition> NodeIDHashTable;
typedef AutoLocker<Node, AutoLockerReadLocking<Node> > NodeReadLocker;
typedef AutoLocker<Node, AutoLockerWriteLocking<Node> > NodeWriteLocker;
#endif // NODE_H

View File

@ -0,0 +1,49 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "Package.h"
#include <stdlib.h>
#include <string.h>
#include "DebugSupport.h"
Package::Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID)
:
fDomain(domain),
fName(NULL),
fNodeID(nodeID),
fDeviceID(deviceID)
{
}
Package::~Package()
{
while (PackageNode* node = fNodes.RemoveHead())
delete node;
free(fName);
}
status_t
Package::Init(const char* name)
{
fName = strdup(name);
if (fName == NULL)
RETURN_ERROR(B_NO_MEMORY);
return B_OK;
}
void
Package::AddNode(PackageNode* node)
{
fNodes.Add(node);
}

View File

@ -0,0 +1,75 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_H
#define PACKAGE_H
#include <util/khash.h>
#include <util/OpenHashTable.h>
#include "PackageNode.h"
class PackageDomain;
class Package {
public:
Package(PackageDomain* domain, dev_t deviceID,
ino_t nodeID);
~Package();
status_t Init(const char* name);
PackageDomain* Domain() const { return fDomain; }
const char* Name() const { return fName; }
Package*& HashTableNext() { return fHashTableNext; }
void AddNode(PackageNode* node);
const PackageNodeList& Nodes() const
{ return fNodes; }
private:
PackageDomain* fDomain;
char* fName;
Package* fHashTableNext;
ino_t fNodeID;
dev_t fDeviceID;
PackageNodeList fNodes;
};
struct PackageHashDefinition {
typedef const char* KeyType;
typedef Package ValueType;
size_t HashKey(const char* key) const
{
return hash_hash_string(key);
}
size_t Hash(const Package* value) const
{
return HashKey(value->Name());
}
bool Compare(const char* key, const Package* value) const
{
return strcmp(value->Name(), key) == 0;
}
Package*& GetLink(Package* value) const
{
return value->HashTableNext();
}
};
typedef BOpenHashTable<PackageHashDefinition> PackageHashTable;
#endif // PACKAGE_H

View File

@ -0,0 +1,33 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "PackageDirectory.h"
PackageDirectory::PackageDirectory()
{
}
PackageDirectory::~PackageDirectory()
{
while (PackageNode* child = fChildren.RemoveHead())
delete child;
}
void
PackageDirectory::AddChild(PackageNode* node)
{
fChildren.Add(node);
}
void
PackageDirectory::RemoveChild(PackageNode* node)
{
fChildren.Remove(node);
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_DIRECTORY_H
#define PACKAGE_DIRECTORY_H
#include "PackageNode.h"
class PackageDirectory : public PackageNode {
public:
PackageDirectory();
virtual ~PackageDirectory();
void AddChild(PackageNode* node);
void RemoveChild(PackageNode* node);
inline PackageNode* FirstChild() const;
inline PackageNode* NextChild(PackageNode* node) const;
const PackageNodeList& Children() const
{ return fChildren; }
private:
PackageNodeList fChildren;
};
PackageNode*
PackageDirectory::FirstChild() const
{
return fChildren.First();
}
PackageNode*
PackageDirectory::NextChild(PackageNode* node) const
{
return fChildren.GetNext(node);
}
#endif // PACKAGE_DIRECTORY_H

View File

@ -0,0 +1,80 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "PackageDomain.h"
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include "DebugSupport.h"
PackageDomain::PackageDomain()
:
fPath(NULL),
fDirFD(-1)
{
}
PackageDomain::~PackageDomain()
{
Package* package = fPackages.Clear(true);
while (package != NULL) {
Package* next = package->HashTableNext();
delete package;
package = next;
}
if (fDirFD >= 0)
close(fDirFD);
free(fPath);
}
status_t
PackageDomain::Init(const char* path)
{
fPath = strdup(path);
if (fPath == NULL)
RETURN_ERROR(B_NO_MEMORY);
status_t error = fPackages.Init();
if (error != B_OK)
return error;
return B_OK;
}
status_t
PackageDomain::Prepare()
{
fDirFD = open(fPath, O_RDONLY);
if (fDirFD < 0) {
ERROR("Failed to open package domain \"%s\"\n", strerror(errno));
return errno;
}
return B_OK;
}
void
PackageDomain::AddPackage(Package* package)
{
fPackages.Insert(package);
}
void
PackageDomain::RemovePackage(Package* package)
{
fPackages.Remove(package);
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_DOMAIN_H
#define PACKAGE_DOMAIN_H
#include <util/DoublyLinkedList.h>
#include "Package.h"
class PackageDomain : public DoublyLinkedListLinkImpl<PackageDomain> {
public:
PackageDomain();
~PackageDomain();
const char* Path() const { return fPath; }
int DirectoryFD() { return fDirFD; }
status_t Init(const char* path);
status_t Prepare();
void AddPackage(Package* package);
void RemovePackage(Package* package);
const PackageHashTable& Packages() const
{ return fPackages; }
private:
char* fPath;
int fDirFD;
PackageHashTable fPackages;
};
#endif // PACKAGE_DOMAIN_H

View File

@ -0,0 +1,17 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "PackageFile.h"
PackageFile::PackageFile()
{
}
PackageFile::~PackageFile()
{
}

View File

@ -0,0 +1,19 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_FILE_H
#define PACKAGE_FILE_H
#include "PackageNode.h"
class PackageFile : public PackageNode {
public:
PackageFile();
virtual ~PackageFile();
};
#endif // PACKAGE_FILE_H

View File

@ -0,0 +1,38 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "PackageNode.h"
#include <stdlib.h>
#include <string.h>
#include "DebugSupport.h"
PackageNode::PackageNode()
:
fParent(NULL),
fName(NULL)
{
}
PackageNode::~PackageNode()
{
free(fName);
}
status_t
PackageNode::Init(PackageDirectory* parent, const char* name)
{
fParent = parent;
fName = strdup(name);
if (fName == NULL)
RETURN_ERROR(B_NO_MEMORY);
return B_OK;
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_NODE_H
#define PACKAGE_NODE_H
#include <SupportDefs.h>
#include <util/SinglyLinkedList.h>
class PackageDirectory;
class PackageNode : public SinglyLinkedListLinkImpl<PackageNode> {
public:
PackageNode();
virtual ~PackageNode();
PackageDirectory* Parent() const { return fParent; }
const char* Name() const { return fName; }
virtual status_t Init(PackageDirectory* parent,
const char* name);
void SetMode(mode_t mode) { fMode = mode; }
mode_t Mode() const { return fMode; }
private:
PackageDirectory* fParent;
char* fName;
mode_t fMode;
};
typedef SinglyLinkedList<PackageNode> PackageNodeList;
#endif // PACKAGE_NODE_H

View File

@ -0,0 +1,17 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "PackageSymlink.h"
PackageSymlink::PackageSymlink()
{
}
PackageSymlink::~PackageSymlink()
{
}

View File

@ -0,0 +1,19 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_SYMLINK_H
#define PACKAGE_SYMLINK_H
#include "PackageNode.h"
class PackageSymlink : public PackageNode {
public:
PackageSymlink();
virtual ~PackageSymlink();
};
#endif // PACKAGE_SYMLINK_H

View File

@ -0,0 +1,41 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "Symlink.h"
#include "PackageSymlink.h"
Symlink::Symlink(ino_t id)
:
Node(id)
{
fMode = S_IFLNK | S_IRUSR | S_IRGRP | S_IROTH;
}
Symlink::~Symlink()
{
}
status_t
Symlink::Init(Directory* parent, const char* name)
{
return Node::Init(parent, name);
}
status_t
Symlink::AddPackageNode(PackageNode* packageNode)
{
if (!S_ISLNK(packageNode->Mode()))
return B_BAD_VALUE;
// TODO:...
return B_OK;
}

View File

@ -0,0 +1,23 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef SYMLINK_H
#define SYMLINK_H
#include "Node.h"
class Symlink : public Node {
public:
Symlink(ino_t id);
virtual ~Symlink();
virtual status_t Init(Directory* parent, const char* name);
virtual status_t AddPackageNode(PackageNode* packageNode);
};
#endif // SYMLINK_H

View File

@ -6,43 +6,257 @@
#include "Volume.h"
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <new>
#include <KernelExport.h>
#include <AutoDeleter.h>
#include "ErrorOutput.h"
#include "FDCloser.h"
#include "PackageEntry.h"
#include "PackageReader.h"
#include "DebugSupport.h"
#include "Directory.h"
#include "File.h"
#include "kernel_interface.h"
#include "PackageDirectory.h"
#include "PackageFile.h"
#include "PackageSymlink.h"
#include "Symlink.h"
// node ID of the root directory
static const ino_t kRootDirectoryID = 1;
// #pragma mark - Job
struct Volume::Job : DoublyLinkedListLinkImpl<Job> {
Job(Volume* volume)
:
fVolume(volume)
{
}
virtual ~Job()
{
}
virtual void Do() = 0;
protected:
Volume* fVolume;
};
// #pragma mark - AddPackageDomainJob
struct Volume::AddPackageDomainJob : Job {
AddPackageDomainJob(Volume* volume, PackageDomain* domain)
:
Job(volume),
fDomain(domain)
{
}
virtual ~AddPackageDomainJob()
{
}
virtual void Do()
{
fVolume->_AddPackageDomain(fDomain);
fDomain = NULL;
}
private:
PackageDomain* fDomain;
};
// #pragma mark - PackageLoaderErrorOutput
struct Volume::PackageLoaderErrorOutput : ErrorOutput {
PackageLoaderErrorOutput(Package* package)
:
fPackage(package)
{
}
virtual void PrintErrorVarArgs(const char* format, va_list args)
{
// TODO:...
}
private:
Package* fPackage;
};
// #pragma mark - PackageLoaderContentHandler
struct Volume::PackageLoaderContentHandler : PackageContentHandler {
PackageLoaderContentHandler(Package* package)
:
fPackage(package),
fErrorOccurred(false)
{
}
status_t Init()
{
return B_OK;
}
virtual status_t HandleEntry(PackageEntry* entry)
{
if (fErrorOccurred)
return B_OK;
PackageDirectory* parentDir = NULL;
if (entry->Parent() != NULL) {
parentDir = dynamic_cast<PackageDirectory*>(
(PackageNode*)entry->Parent()->UserToken());
if (parentDir == NULL)
RETURN_ERROR(B_BAD_DATA);
}
// create the package node
PackageNode* node;
if (S_ISREG(entry->Mode())) {
node = new(std::nothrow) PackageFile;
} else if (S_ISLNK(entry->Mode())) {
node = new(std::nothrow) PackageSymlink;
} else if (S_ISDIR(entry->Mode())) {
node = new(std::nothrow) PackageDirectory;
} else
RETURN_ERROR(B_BAD_DATA);
if (node == NULL)
RETURN_ERROR(B_NO_MEMORY);
ObjectDeleter<PackageNode> nodeDeleter(node);
status_t error = node->Init(parentDir, entry->Name());
if (error != B_OK)
RETURN_ERROR(error);
node->SetMode(entry->Mode());
// add it to the parent directory
if (parentDir != NULL)
parentDir->AddChild(node);
else
fPackage->AddNode(node);
nodeDeleter.Detach();
entry->SetUserToken(node);
return B_OK;
}
virtual status_t HandleEntryAttribute(PackageEntry* entry,
PackageEntryAttribute* attribute)
{
// TODO:...
return B_OK;
}
virtual status_t HandleEntryDone(PackageEntry* entry)
{
return B_OK;
}
virtual void HandleErrorOccurred()
{
fErrorOccurred = true;
}
private:
Package* fPackage;
bool fErrorOccurred;
};
// #pragma mark - Volume
Volume::Volume(fs_volume* fsVolume)
:
fFSVolume(fsVolume),
fRootDirectory(NULL)
fRootDirectory(NULL),
fPackageLoader(-1),
fNextNodeID(kRootDirectoryID + 1),
fTerminating(false)
{
rw_lock_init(&fLock, "packagefs volume");
mutex_init(&fJobQueueLock, "packagefs volume job queue");
fJobQueueCondition.Init(this, "packagefs volume job queue");
}
Volume::~Volume()
{
delete fRootDirectory;
_TerminatePackageLoader();
while (PackageDomain* packageDomain = fPackageDomains.RemoveHead())
delete packageDomain;
if (fRootDirectory != NULL)
fRootDirectory->ReleaseReference();
mutex_destroy(&fJobQueueLock);
rw_lock_destroy(&fLock);
}
status_t
Volume::Mount()
{
// init the node table
status_t error = fNodes.Init();
if (error != B_OK)
RETURN_ERROR(error);
// create the root node
fRootDirectory = new(std::nothrow) Directory(kRootDirectoryID);
if (fRootDirectory == NULL)
return B_NO_MEMORY;
RETURN_ERROR(B_NO_MEMORY);
fNodes.Insert(fRootDirectory);
// publish it
status_t error = publish_vnode(fFSVolume, fRootDirectory->ID(),
fRootDirectory, &gPackageFSVnodeOps, S_IFDIR, 0);
// create default package domains
// TODO: Get them from the mount parameters instead!
error = _AddInitialPackageDomain("/boot/common/packages");
if (error != B_OK)
RETURN_ERROR(error);
// spawn package loader thread
fPackageLoader = spawn_kernel_thread(&_PackageLoaderEntry,
"package loader", B_NORMAL_PRIORITY, this);
if (fPackageLoader < 0)
RETURN_ERROR(fPackageLoader);
// publish the root node
fRootDirectory->AcquireReference();
error = PublishVNode(fRootDirectory);
if (error != B_OK) {
fRootDirectory->ReleaseReference();
return error;
}
// run the package loader
resume_thread(fPackageLoader);
return B_OK;
}
@ -51,4 +265,342 @@ Volume::Mount()
void
Volume::Unmount()
{
_TerminatePackageLoader();
}
status_t
Volume::GetVNode(ino_t nodeID, Node*& _node)
{
return get_vnode(fFSVolume, nodeID, (void**)&_node);
}
status_t
Volume::PublishVNode(Node* node)
{
return publish_vnode(fFSVolume, node->ID(), node, &gPackageFSVnodeOps,
node->Mode() & S_IFMT, 0);
}
status_t
Volume::AddPackageDomain(const char* path)
{
PackageDomain* packageDomain = new(std::nothrow) PackageDomain;
if (packageDomain == NULL)
RETURN_ERROR(B_NO_MEMORY);
ObjectDeleter<PackageDomain> packageDomainDeleter(packageDomain);
status_t error = packageDomain->Init(path);
if (error != B_OK)
return error;
Job* job = new(std::nothrow) AddPackageDomainJob(this, packageDomain);
if (job == NULL)
RETURN_ERROR(B_NO_MEMORY);
packageDomainDeleter.Detach();
_PushJob(job);
return B_OK;
}
/*static*/ status_t
Volume::_PackageLoaderEntry(void* data)
{
return ((Volume*)data)->_PackageLoader();
}
status_t
Volume::_PackageLoader()
{
while (!fTerminating) {
MutexLocker jobQueueLocker(fJobQueueLock);
Job* job = fJobQueue.RemoveHead();
if (job == NULL) {
// no job yet -- wait for someone notifying us
ConditionVariableEntry waitEntry;
fJobQueueCondition.Add(&waitEntry);
jobQueueLocker.Unlock();
waitEntry.Wait();
continue;
}
// do the job
jobQueueLocker.Unlock();
job->Do();
delete job;
}
return B_OK;
}
void
Volume::_TerminatePackageLoader()
{
fTerminating = true;
if (fPackageLoader >= 0) {
MutexLocker jobQueueLocker(fJobQueueLock);
fJobQueueCondition.NotifyOne();
jobQueueLocker.Unlock();
wait_for_thread(fPackageLoader, NULL);
fPackageLoader = -1;
}
// empty the job queue
while (Job* job = fJobQueue.RemoveHead())
delete job;
}
void
Volume::_PushJob(Job* job)
{
MutexLocker jobQueueLocker(fJobQueueLock);
fJobQueue.Add(job);
}
status_t
Volume::_AddInitialPackageDomain(const char* path)
{
PackageDomain* domain = new(std::nothrow) PackageDomain;
if (domain == NULL)
RETURN_ERROR(B_NO_MEMORY);
ObjectDeleter<PackageDomain> domainDeleter(domain);
status_t error = domain->Init(path);
if (error != B_OK)
return error;
return _AddPackageDomain(domainDeleter.Detach());
}
status_t
Volume::_AddPackageDomain(PackageDomain* domain)
{
ObjectDeleter<PackageDomain> domainDeleter(domain);
// prepare the package domain
status_t error = domain->Prepare();
if (error != B_OK) {
ERROR("Failed to prepare package domain \"%s\": %s\n",
domain->Path(), strerror(errno));
return errno;
}
// TODO: Start monitoring the directory!
// iterate through the dir and create packages
DIR* dir = opendir(domain->Path());
if (dir == NULL) {
ERROR("Failed to open package domain directory \"%s\": %s\n",
domain->Path(), strerror(errno));
return errno;
}
CObjectDeleter<DIR, int> dirCloser(dir, closedir);
while (dirent* entry = readdir(dir)) {
// skip "." and ".."
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
// check whether the entry is a file
struct stat st;
if (fstatat(domain->DirectoryFD(), entry->d_name, &st,
AT_SYMLINK_NOFOLLOW) < 0
|| !S_ISREG(st.st_mode)) {
continue;
}
// create a package
Package* package = new(std::nothrow) Package(domain, st.st_dev,
st.st_ino);
if (package == NULL)
RETURN_ERROR(B_NO_MEMORY);
ObjectDeleter<Package> packageDeleter(package);
status_t error = package->Init(entry->d_name);
if (error != B_OK)
return error;
error = _LoadPackage(package);
if (error != B_OK)
continue;
domain->AddPackage(packageDeleter.Detach());
}
// add the packages to the node tree
VolumeWriteLocker volumeLocker(this);
for (PackageHashTable::Iterator it = domain->Packages().GetIterator();
Package* package = it.Next();) {
error = _AddPackageContent(package);
if (error != B_OK) {
// TODO: Remove the already added packages!
return error;
}
}
fPackageDomains.Add(domainDeleter.Detach());
return B_OK;
}
status_t
Volume::_LoadPackage(Package* package)
{
// open package file
int fd = openat(package->Domain()->DirectoryFD(), package->Name(),
O_RDONLY);
if (fd < 0) {
ERROR("Failed to open package file \"%s\"\n", package->Name());
return errno;
}
// TODO: Verify that it's still the same file.
FDCloser fdCloser(fd);
// open package
PackageLoaderErrorOutput errorOutput(package);
PackageReader packageReader(&errorOutput);
status_t error = packageReader.Init(fd, false);
if (error != B_OK)
return error;
// parse content
PackageLoaderContentHandler handler(package);
error = handler.Init();
if (error != B_OK)
return error;
error = packageReader.ParseContent(&handler);
if (error != B_OK)
return error;
return B_OK;
}
status_t
Volume::_AddPackageContent(Package* package)
{
for (PackageNodeList::Iterator it = package->Nodes().GetIterator();
PackageNode* node = it.Next();) {
status_t error = _AddPackageContentRootNode(package, node);
if (error != B_OK) {
// TODO: Remove already added nodes!
return error;
}
}
// TODO: Recursively add the nodes!
return B_OK;
}
status_t
Volume::_AddPackageContentRootNode(Package* package, PackageNode* packageNode)
{
Directory* directory = fRootDirectory;
directory->WriteLock();
do {
Node* node;
status_t error = _AddPackageNode(directory, packageNode, node);
if (error != B_OK) {
// TODO: Remove already added nodes!
return error;
}
// recursive into directory
if (PackageDirectory* packageDirectory
= dynamic_cast<PackageDirectory*>(packageNode)) {
if (packageDirectory->FirstChild() != NULL) {
directory = dynamic_cast<Directory*>(node);
packageNode = packageDirectory->FirstChild();
directory->WriteLock();
continue;
}
}
// continue with the next available (descendent's) sibling
do {
PackageDirectory* packageDirectory = packageNode->Parent();
if (PackageNode* sibling
= packageDirectory->NextChild(packageNode)) {
packageNode = sibling;
break;
}
// no more siblings -- go back up the tree
packageNode = packageDirectory;
directory->WriteUnlock();
directory = directory->Parent();
// the parent is still locked, so this is safe
} while (packageNode != NULL);
} while (packageNode != NULL);
return B_OK;
}
status_t
Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
Node*& _node)
{
Node* node = directory->FindChild(packageNode->Name());
if (node == NULL) {
status_t error = _CreateNode(packageNode->Mode(), directory,
packageNode->Name(), node);
if (error != B_OK)
return error;
}
status_t error = node->AddPackageNode(packageNode);
if (error != B_OK)
return error;
// TODO: Remove the node, if created before!
_node = node;
return B_OK;
}
status_t
Volume::_CreateNode(mode_t mode, Directory* parent, const char* name,
Node*& _node)
{
Node* node;
if (S_ISREG(mode))
node = new(std::nothrow) File(fNextNodeID++);
else if (S_ISLNK(mode))
node = new(std::nothrow) Symlink(fNextNodeID++);
else if (S_ISDIR(mode))
node = new(std::nothrow) Directory(fNextNodeID++);
else
RETURN_ERROR(B_UNSUPPORTED);
if (node == NULL)
RETURN_ERROR(B_NO_MEMORY);
ObjectDeleter<Node> nodeDeleter(node);
status_t error = node->Init(parent, name);
if (error != B_OK)
return error;
parent->AddChild(node);
fNodes.Insert(node);
// we keep the initial node reference for this table
_node = nodeDeleter.Detach();
return B_OK;
}

View File

@ -8,8 +8,17 @@
#include <fs_interface.h>
#include <condition_variable.h>
#include <lock.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h>
#include "Node.h"
#include "PackageDomain.h"
class Directory;
class Node;
class Volume {
@ -17,15 +26,105 @@ public:
Volume(fs_volume* fsVolume);
~Volume();
inline bool ReadLock();
inline void ReadUnlock();
inline bool WriteLock();
inline void WriteUnlock();
fs_volume* FSVolume() const { return fFSVolume; }
dev_t ID() const { return fFSVolume->id; }
Directory* RootDirectory() const { return fRootDirectory; }
status_t Mount();
void Unmount();
Directory* RootDirectory() const { return fRootDirectory; }
Node* FindNode(ino_t nodeID) const
{ return fNodes.Lookup(nodeID); }
// VFS wrappers
status_t GetVNode(ino_t nodeID, Node*& _node);
status_t PublishVNode(Node* node);
status_t AddPackageDomain(const char* path);
private:
struct Job;
struct AddPackageDomainJob;
struct PackageLoaderErrorOutput;
struct PackageLoaderContentHandler;
typedef DoublyLinkedList<Job> JobList;
typedef DoublyLinkedList<PackageDomain> PackageDomainList;
private:
static status_t _PackageLoaderEntry(void* data);
status_t _PackageLoader();
void _TerminatePackageLoader();
void _PushJob(Job* job);
status_t _AddInitialPackageDomain(const char* path);
status_t _AddPackageDomain(PackageDomain* domain);
status_t _LoadPackage(Package* package);
status_t _AddPackageContent(Package* package);
status_t _AddPackageContentRootNode(Package* package,
PackageNode* node);
status_t _AddPackageNode(Directory* directory,
PackageNode* packageNode, Node*& _node);
status_t _CreateNode(mode_t mode, Directory* parent,
const char* name, Node*& _node);
private:
rw_lock fLock;
fs_volume* fFSVolume;
Directory* fRootDirectory;
thread_id fPackageLoader;
PackageDomainList fPackageDomains;
NodeIDHashTable fNodes;
JobList fJobQueue;
mutex fJobQueueLock;
ConditionVariable fJobQueueCondition;
ino_t fNextNodeID;
volatile bool fTerminating;
};
bool
Volume::ReadLock()
{
return rw_lock_read_lock(&fLock) == B_OK;
}
void
Volume::ReadUnlock()
{
rw_lock_read_unlock(&fLock);
}
bool
Volume::WriteLock()
{
return rw_lock_write_lock(&fLock) == B_OK;
}
void
Volume::WriteUnlock()
{
rw_lock_write_unlock(&fLock);
}
typedef AutoLocker<Volume, AutoLockerReadLocking<Volume> > VolumeReadLocker;
typedef AutoLocker<Volume, AutoLockerWriteLocking<Volume> > VolumeWriteLocker;
#endif // VOLUME_H

View File

@ -6,6 +6,8 @@
#include "kernel_interface.h"
#include <dirent.h>
#include <new>
#include <fs_info.h>
@ -22,6 +24,38 @@
static const uint32 kOptimalIOSize = 64 * 1024;
// #pragma mark - helper functions
static bool
is_user_in_group(gid_t gid)
{
gid_t groups[NGROUPS_MAX];
int groupCount = getgroups(NGROUPS_MAX, groups);
for (int i = 0; i < groupCount; i++) {
if (gid == groups[i])
return true;
}
return (gid == getegid());
}
static bool
set_dirent_name(struct dirent* buffer, size_t bufferSize, const char* name,
size_t nameLen)
{
size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer;
if (length > bufferSize)
return false;
memcpy(buffer->d_name, name, nameLen);
buffer->d_name[nameLen] = '\0';
buffer->d_reclen = length;
return true;
}
// #pragma mark - Volume
@ -92,7 +126,34 @@ packagefs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* entryName,
FUNCTION("volume: %p, dir: %p (%lld), entry: \"%s\"\n", volume, dir,
dir->ID(), entryName);
return B_UNSUPPORTED;
if (!S_ISDIR(dir->Mode()))
return B_NOT_A_DIRECTORY;
// resolve "."
if (strcmp(entryName, ".") == 0) {
Node* node;
*_vnid = dir->ID();
return volume->GetVNode(*_vnid, node);
}
// resolve ".."
if (strcmp(entryName, "..") == 0) {
Node* node;
*_vnid = dir->Parent()->ID();
return volume->GetVNode(*_vnid, node);
}
// resolve normal entries -- look up the node
NodeReadLocker dirLocker(dir);
Node* node = dynamic_cast<Directory*>(dir)->FindChild(entryName);
if (node == NULL)
return B_ENTRY_NOT_FOUND;
BReference<Node> nodeReference(node);
dirLocker.Unlock();
// get the vnode reference
*_vnid = node->ID();
RETURN_ERROR(volume->GetVNode(*_vnid, node));
}
@ -104,14 +165,33 @@ packagefs_get_vnode(fs_volume* fsVolume, ino_t vnid, fs_vnode* fsNode,
FUNCTION("volume: %p, vnid: %lld\n", volume, vnid);
return B_UNSUPPORTED;
VolumeReadLocker volumeLocker(volume);
Node* node = volume->FindNode(vnid);
if (node == NULL)
return B_ENTRY_NOT_FOUND;
node->AcquireReference();
fsNode->private_node = node;
fsNode->ops = &gPackageFSVnodeOps;
*_type = node->Mode() & S_IFMT;
*_flags = 0;
return B_OK;
}
static status_t
packagefs_put_vnode(fs_volume* fs, fs_vnode* _node, bool reenter)
packagefs_put_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter)
{
return B_UNSUPPORTED;
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p\n", volume, node);
TOUCH(volume);
node->ReleaseReference();
return B_OK;
}
@ -119,7 +199,7 @@ packagefs_put_vnode(fs_volume* fs, fs_vnode* _node, bool reenter)
static status_t
packagefs_read_symlink(fs_volume* fs, fs_vnode* _node, char* buffer,
packagefs_read_symlink(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
size_t* bufferSize)
{
return B_UNSUPPORTED;
@ -127,9 +207,46 @@ packagefs_read_symlink(fs_volume* fs, fs_vnode* _node, char* buffer,
static status_t
packagefs_access(fs_volume* fs, fs_vnode* _node, int mode)
packagefs_access(fs_volume* fsVolume, fs_vnode* fsNode, int mode)
{
return B_UNSUPPORTED;
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
TOUCH(volume);
FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID());
TOUCH(volume);
// write access requested?
if (mode & W_OK)
return B_READ_ONLY_DEVICE;
// get node permissions
int userPermissions = (node->Mode() & S_IRWXU) >> 6;
int groupPermissions = (node->Mode() & S_IRWXG) >> 3;
int otherPermissions = node->Mode() & S_IRWXO;
// get the permissions for this uid/gid
int permissions = 0;
uid_t uid = geteuid();
if (uid == 0) {
// user is root
// root has always read/write permission, but at least one of the
// X bits must be set for execute permission
permissions = userPermissions | groupPermissions | otherPermissions
| S_IROTH | S_IWOTH;
} else if (uid == node->UserID()) {
// user is node owner
permissions = userPermissions;
} else if (is_user_in_group(node->GroupID())) {
// user is in owning group
permissions = groupPermissions;
} else {
// user is one of the others
permissions = otherPermissions;
}
return (mode & ~permissions) ? B_NOT_ALLOWED : B_OK;
}
@ -140,9 +257,10 @@ packagefs_read_stat(fs_volume* fsVolume, fs_vnode* fsNode, struct stat* st)
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID());
TOUCH(volume);
// TODO: Fill in correctly!
st->st_mode = S_IFDIR;
st->st_mode = node->Mode();
st->st_nlink = 1;
st->st_uid = 0;
st->st_gid = 0;
@ -161,23 +279,35 @@ packagefs_read_stat(fs_volume* fsVolume, fs_vnode* fsNode, struct stat* st)
static status_t
packagefs_open(fs_volume* fs, fs_vnode* _node, int openMode, void** cookie)
packagefs_open(fs_volume* fsVolume, fs_vnode* fsNode, int openMode,
void** _cookie)
{
return B_UNSUPPORTED;
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%lld), openMode %#x\n", volume, node,
node->ID(), openMode);
TOUCH(volume);
TOUCH(node);
// TODO: Implement it for real!
*_cookie = NULL;
return B_OK;
}
static status_t
packagefs_close(fs_volume* fs, fs_vnode* _node, void* cookie)
{
return B_UNSUPPORTED;
return B_OK;
}
static status_t
packagefs_free_cookie(fs_volume* fs, fs_vnode* _node, void* cookie)
{
return B_UNSUPPORTED;
return B_OK;
}
@ -192,39 +322,218 @@ packagefs_read(fs_volume* fs, fs_vnode* _node, void* cookie, off_t pos,
// #pragma mark - Directories
struct DirectoryCookie : DirectoryIterator {
Directory* directory;
int32 state;
bool registered;
DirectoryCookie(Directory* directory)
:
directory(directory),
state(0),
registered(false)
{
Rewind();
}
~DirectoryCookie()
{
if (registered)
directory->RemoveDirectoryIterator(this);
}
void Rewind()
{
if (registered)
directory->RemoveDirectoryIterator(this);
registered = false;
state = 0;
node = directory;
}
Node* Current(const char*& _name) const
{
if (node == NULL)
return NULL;
if (state == 0)
_name = ".";
else if (state == 1)
_name = "..";
else
_name = node->Name();
return node;
}
Node* Next()
{
if (state == 0) {
state = 1;
node = directory->Parent();
if (node == NULL)
node = directory;
return node;
}
if (state == 1) {
node = directory->FirstChild();
state = 2;
} else {
if (node != NULL)
node = directory->NextChild(node);
}
if (node == NULL) {
if (registered) {
directory->RemoveDirectoryIterator(this);
registered = false;
}
return NULL;
}
if (!registered) {
directory->AddDirectoryIterator(this);
registered = true;
}
return node;
}
};
static status_t
packagefs_open_dir(fs_volume* fs, fs_vnode* _node, void** cookie)
packagefs_open_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie)
{
return B_UNSUPPORTED;
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID());
if (!S_ISDIR(node->Mode()))
return B_NOT_A_DIRECTORY;
Directory* dir = dynamic_cast<Directory*>(node);
// create a cookie
DirectoryCookie* cookie = new(std::nothrow) DirectoryCookie(dir);
if (cookie == NULL)
RETURN_ERROR(B_NO_MEMORY);
*_cookie = cookie;
return B_OK;
}
static status_t
packagefs_close_dir(fs_volume* fs, fs_vnode* _node, void* cookie)
packagefs_close_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
{
return B_UNSUPPORTED;
return B_OK;
}
static status_t
packagefs_free_dir_cookie(fs_volume* fs, fs_vnode* _node, void* cookie)
packagefs_free_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
{
return B_UNSUPPORTED;
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
NodeWriteLocker dirLocker(node);
delete cookie;
return B_OK;
}
static status_t
packagefs_read_dir(fs_volume* fs, fs_vnode* _node, void* cookie,
struct dirent* buffer, size_t bufferSize, uint32* count)
packagefs_read_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
struct dirent* buffer, size_t bufferSize, uint32* _count)
{
return B_UNSUPPORTED;
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
NodeWriteLocker dirLocker(cookie->directory);
uint32 maxCount = *_count;
uint32 count = 0;
dirent* previousEntry = NULL;
const char* name;
while (Node* child = cookie->Current(name)) {
// don't read more entries than requested
if (count >= maxCount)
break;
// align the buffer for subsequent entries
if (count > 0) {
addr_t offset = (addr_t)buffer % 8;
if (offset > 0) {
offset = 8 - offset;
if (bufferSize <= offset)
break;
previousEntry->d_reclen += offset;
buffer = (dirent*)((addr_t)buffer + offset);
bufferSize -= offset;
}
}
// fill in the entry name -- checks whether the entry fits into the
// buffer
if (!set_dirent_name(buffer, bufferSize, name, strlen(name))) {
if (count == 0)
RETURN_ERROR(B_BUFFER_OVERFLOW);
break;
}
// fill in the other data
buffer->d_dev = volume->ID();
buffer->d_ino = child->ID();
count++;
previousEntry = buffer;
bufferSize -= buffer->d_reclen;
buffer = (dirent*)((addr_t)buffer + buffer->d_reclen);
cookie->Next();
}
*_count = count;
return B_OK;
}
static status_t
packagefs_rewind_dir(fs_volume* fs, fs_vnode* _node, void* cookie)
packagefs_rewind_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
{
return B_UNSUPPORTED;
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
NodeWriteLocker dirLocker(node);
cookie->Rewind();
return B_OK;
}
@ -292,7 +601,7 @@ fs_vnode_ops gPackageFSVnodeOps = {
&packagefs_lookup,
NULL, // get_vnode_name,
&packagefs_put_vnode,
NULL, // remove_vnode,
&packagefs_put_vnode, // remove_vnode -- same as put_vnode
/* VM file access */
NULL, // can_page,

View File

@ -1,13 +1,23 @@
SubDir HAIKU_TOP src add-ons kernel file_systems packagefs userland ;
UseLibraryHeaders zlib ;
UsePrivateKernelHeaders ;
UsePrivateHeaders haiku_package shared ;
DEFINES += B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT ;
# TODO: Remove when it is complete!
SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) ] ;
UsePrivateHeaders shared ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src bin package ] ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src bin package compression ] ;
Addon <userland>packagefs
: $(HAIKU_PACKAGE_FS_SOURCES)
: libuserlandfs_haiku_kernel.so $(TARGET_LIBSUPC++)
:
$(HAIKU_PACKAGE_FS_SOURCES)
$(HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES)
: libuserlandfs_haiku_kernel.so $(TARGET_LIBSUPC++) libz.a
;