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:
parent
82df777b3d
commit
cc32c48494
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
41
src/add-ons/kernel/file_systems/packagefs/File.cpp
Normal file
41
src/add-ons/kernel/file_systems/packagefs/File.cpp
Normal 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;
|
||||
}
|
23
src/add-ons/kernel/file_systems/packagefs/File.h
Normal file
23
src/add-ons/kernel/file_systems/packagefs/File.h
Normal 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
|
@ -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
|
||||
;
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
49
src/add-ons/kernel/file_systems/packagefs/Package.cpp
Normal file
49
src/add-ons/kernel/file_systems/packagefs/Package.cpp
Normal 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);
|
||||
}
|
75
src/add-ons/kernel/file_systems/packagefs/Package.h
Normal file
75
src/add-ons/kernel/file_systems/packagefs/Package.h
Normal 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
|
@ -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);
|
||||
}
|
45
src/add-ons/kernel/file_systems/packagefs/PackageDirectory.h
Normal file
45
src/add-ons/kernel/file_systems/packagefs/PackageDirectory.h
Normal 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
|
80
src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp
Normal file
80
src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp
Normal 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);
|
||||
}
|
38
src/add-ons/kernel/file_systems/packagefs/PackageDomain.h
Normal file
38
src/add-ons/kernel/file_systems/packagefs/PackageDomain.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_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
|
17
src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp
Normal file
17
src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp
Normal 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()
|
||||
{
|
||||
}
|
19
src/add-ons/kernel/file_systems/packagefs/PackageFile.h
Normal file
19
src/add-ons/kernel/file_systems/packagefs/PackageFile.h
Normal 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
|
38
src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp
Normal file
38
src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp
Normal 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;
|
||||
}
|
41
src/add-ons/kernel/file_systems/packagefs/PackageNode.h
Normal file
41
src/add-ons/kernel/file_systems/packagefs/PackageNode.h
Normal 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
|
17
src/add-ons/kernel/file_systems/packagefs/PackageSymlink.cpp
Normal file
17
src/add-ons/kernel/file_systems/packagefs/PackageSymlink.cpp
Normal 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()
|
||||
{
|
||||
}
|
19
src/add-ons/kernel/file_systems/packagefs/PackageSymlink.h
Normal file
19
src/add-ons/kernel/file_systems/packagefs/PackageSymlink.h
Normal 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
|
41
src/add-ons/kernel/file_systems/packagefs/Symlink.cpp
Normal file
41
src/add-ons/kernel/file_systems/packagefs/Symlink.cpp
Normal 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;
|
||||
}
|
23
src/add-ons/kernel/file_systems/packagefs/Symlink.h
Normal file
23
src/add-ons/kernel/file_systems/packagefs/Symlink.h
Normal 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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
;
|
||||
|
Loading…
Reference in New Issue
Block a user