* Extract the attributes from the package files and attach them as

PackageNodeAttribute to the PackageNodes.
* Implemented the attribute FS interface hooks.
* Made Package and PackageNode BReferenceable.
* Fixed the reference management for Node.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34119 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-11-18 22:44:20 +00:00
parent 1892e95632
commit 46776004f7
16 changed files with 577 additions and 22 deletions

View File

@ -111,6 +111,13 @@ Directory::AddPackageNode(PackageNode* packageNode)
}
PackageNode*
Directory::GetPackageNode()
{
return fPackageDirectories.Head();
}
status_t
Directory::Read(off_t offset, void* buffer, size_t* bufferSize)
{
@ -123,6 +130,7 @@ Directory::AddChild(Node* node)
{
fChildTable.Insert(node);
fChildList.Add(node);
node->AcquireReference();
}
@ -133,6 +141,7 @@ Directory::RemoveChild(Node* node)
fChildTable.Remove(node);
fChildList.Remove(node);
node->ReleaseReference();
// adjust directory iterators pointing to the removed child
for (DirectoryIteratorList::Iterator it = fIterators.GetIterator();

View File

@ -42,6 +42,8 @@ public:
virtual status_t AddPackageNode(PackageNode* packageNode);
virtual PackageNode* GetPackageNode();
virtual status_t Read(off_t offset, void* buffer,
size_t* bufferSize);

View File

@ -23,6 +23,7 @@ HAIKU_PACKAGE_FS_SOURCES =
PackageFile.cpp
PackageLeafNode.cpp
PackageNode.cpp
PackageNodeAttribute.cpp
PackageSymlink.cpp
Volume.cpp
;

View File

@ -102,6 +102,13 @@ LeafNode::AddPackageNode(PackageNode* packageNode)
}
PackageNode*
LeafNode::GetPackageNode()
{
return fPackageNodes.Head();
}
status_t
LeafNode::Read(off_t offset, void* buffer, size_t* bufferSize)
{

View File

@ -28,6 +28,8 @@ public:
virtual status_t AddPackageNode(PackageNode* packageNode);
virtual PackageNode* GetPackageNode();
virtual status_t Read(off_t offset, void* buffer,
size_t* bufferSize);

View File

@ -53,6 +53,8 @@ public:
virtual status_t AddPackageNode(PackageNode* packageNode) = 0;
virtual PackageNode* GetPackageNode() = 0;
virtual status_t Read(off_t offset, void* buffer,
size_t* bufferSize) = 0;

View File

@ -34,7 +34,7 @@ Package::Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID)
Package::~Package()
{
while (PackageNode* node = fNodes.RemoveHead())
delete node;
node->ReleaseReference();
free(fName);
@ -57,6 +57,7 @@ void
Package::AddNode(PackageNode* node)
{
fNodes.Add(node);
node->AcquireReference();
}

View File

@ -6,6 +6,8 @@
#define PACKAGE_H
#include <Referenceable.h>
#include <util/khash.h>
#include <util/OpenHashTable.h>
@ -17,7 +19,7 @@
class PackageDomain;
class Package {
class Package : public BReferenceable {
public:
Package(PackageDomain* domain, dev_t deviceID,
ino_t nodeID);

View File

@ -17,7 +17,7 @@ PackageDirectory::PackageDirectory(Package* package, mode_t mode)
PackageDirectory::~PackageDirectory()
{
while (PackageNode* child = fChildren.RemoveHead())
delete child;
child->ReleaseReference();
}
@ -25,6 +25,7 @@ void
PackageDirectory::AddChild(PackageNode* node)
{
fChildren.Add(node);
node->AcquireReference();
}
@ -32,4 +33,5 @@ void
PackageDirectory::RemoveChild(PackageNode* node)
{
fChildren.Remove(node);
node->ReleaseReference();
}

View File

@ -27,7 +27,7 @@ PackageDomain::~PackageDomain()
Package* package = fPackages.Clear(true);
while (package != NULL) {
Package* next = package->HashTableNext();
delete package;
package->ReleaseReference();
package = next;
}
@ -70,6 +70,7 @@ void
PackageDomain::AddPackage(Package* package)
{
fPackages.Insert(package);
package->AcquireReference();
}
@ -77,4 +78,5 @@ void
PackageDomain::RemovePackage(Package* package)
{
fPackages.Remove(package);
package->ReleaseReference();
}

View File

@ -26,6 +26,9 @@ PackageNode::PackageNode(Package* package, mode_t mode)
PackageNode::~PackageNode()
{
while (PackageNodeAttribute* attribute = fAttributes.RemoveHead())
delete attribute;
free(fName);
}
@ -60,3 +63,30 @@ PackageNode::FileSize() const
{
return 0;
}
void
PackageNode::AddAttribute(PackageNodeAttribute* attribute)
{
fAttributes.Add(attribute);
}
void
PackageNode::RemoveAttribute(PackageNodeAttribute* attribute)
{
fAttributes.Remove(attribute);
}
PackageNodeAttribute*
PackageNode::FindAttribute(const char* name) const
{
for (PackageNodeAttributeList::ConstIterator it = fAttributes.GetIterator();
PackageNodeAttribute* attribute = it.Next();) {
if (strcmp(attribute->Name(), name) == 0)
return attribute;
}
return NULL;
}

View File

@ -8,22 +8,26 @@
#include <sys/stat.h>
#include <SupportDefs.h>
#include <Referenceable.h>
#include <util/SinglyLinkedList.h>
#include "PackageNodeAttribute.h"
class Package;
class PackageDirectory;
class PackageNode : public SinglyLinkedListLinkImpl<PackageNode> {
class PackageNode : public BReferenceable,
public SinglyLinkedListLinkImpl<PackageNode> {
public:
PackageNode(Package* package, mode_t mode);
virtual ~PackageNode();
PackageDirectory* Parent() const { return fParent; }
const char* Name() const { return fName; }
Package* GetPackage() const { return fPackage; }
PackageDirectory* Parent() const { return fParent; }
const char* Name() const { return fName; }
virtual status_t Init(PackageDirectory* parent,
const char* name);
@ -46,6 +50,15 @@ public:
virtual off_t FileSize() const;
void AddAttribute(PackageNodeAttribute* attribute);
void RemoveAttribute(
PackageNodeAttribute* attribute);
const PackageNodeAttributeList& Attributes() const
{ return fAttributes; }
PackageNodeAttribute* FindAttribute(const char* name) const;
protected:
Package* fPackage;
PackageDirectory* fParent;
@ -54,6 +67,7 @@ protected:
uid_t fUserID;
gid_t fGroupID;
timespec fModifiedTime;
PackageNodeAttributeList fAttributes;
};

View File

@ -0,0 +1,35 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "PackageNodeAttribute.h"
#include <stdlib.h>
#include <string.h>
PackageNodeAttribute::PackageNodeAttribute(PackageNode* parent, uint32 type,
const PackageData& data)
:
fData(data),
fParent(parent),
fName(NULL),
fType(type)
{
}
PackageNodeAttribute::~PackageNodeAttribute()
{
free(fName);
}
status_t
PackageNodeAttribute::Init(const char* name)
{
fName = strdup(name);
return fName != NULL ? B_OK : B_NO_MEMORY;
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_NODE_ATTRIBUTE_H
#define PACKAGE_NODE_ATTRIBUTE_H
#include <util/DoublyLinkedList.h>
#include "PackageData.h"
class PackageNode;
class PackageNodeAttribute
: public DoublyLinkedListLinkImpl<PackageNodeAttribute> {
public:
PackageNodeAttribute(PackageNode* parent,
uint32 type, const PackageData& data);
~PackageNodeAttribute();
PackageNode* Parent() const { return fParent; }
const char* Name() const { return fName; }
uint32 Type() const { return fType; }
const PackageData& Data() const { return fData; }
status_t Init(const char* name);
protected:
PackageData fData;
PackageNode* fParent;
char* fName;
uint32 fType;
};
typedef DoublyLinkedList<PackageNodeAttribute> PackageNodeAttributeList;
#endif // PACKAGE_NODE_ATTRIBUTE_H

View File

@ -21,6 +21,7 @@
#include "ErrorOutput.h"
#include "FDCloser.h"
#include "PackageEntry.h"
#include "PackageEntryAttribute.h"
#include "PackageReader.h"
#include "DebugSupport.h"
@ -164,7 +165,7 @@ struct Volume::PackageLoaderContentHandler : PackageContentHandler {
if (node == NULL)
RETURN_ERROR(B_NO_MEMORY);
ObjectDeleter<PackageNode> nodeDeleter(node);
BReference<PackageNode> nodeReference(node, true);
error = node->Init(parentDir, entry->Name());
if (error != B_OK)
@ -178,7 +179,6 @@ struct Volume::PackageLoaderContentHandler : PackageContentHandler {
else
fPackage->AddNode(node);
nodeDeleter.Detach();
entry->SetUserToken(node);
return B_OK;
@ -187,7 +187,24 @@ struct Volume::PackageLoaderContentHandler : PackageContentHandler {
virtual status_t HandleEntryAttribute(PackageEntry* entry,
PackageEntryAttribute* attribute)
{
// TODO:...
if (fErrorOccurred)
return B_OK;
PackageNode* node = (PackageNode*)entry->UserToken();
PackageNodeAttribute* nodeAttribute = new(std::nothrow)
PackageNodeAttribute(node, attribute->Type(), attribute->Data());
if (nodeAttribute == NULL)
RETURN_ERROR(B_NO_MEMORY)
status_t error = nodeAttribute->Init(attribute->Name());
if (error != B_OK) {
delete nodeAttribute;
RETURN_ERROR(error);
}
node->AddAttribute(nodeAttribute);
return B_OK;
}
@ -231,6 +248,14 @@ Volume::~Volume()
while (PackageDomain* packageDomain = fPackageDomains.RemoveHead())
delete packageDomain;
// remove all nodes from the ID hash table
Node* node = fNodes.Clear(true);
while (node != NULL) {
Node* next = node->IDHashTableNext();
node->ReleaseReference();
node = next;
}
if (fRootDirectory != NULL)
fRootDirectory->ReleaseReference();
@ -444,7 +469,7 @@ Volume::_AddPackageDomain(PackageDomain* domain)
st.st_ino);
if (package == NULL)
RETURN_ERROR(B_NO_MEMORY);
ObjectDeleter<Package> packageDeleter(package);
BReference<Package> packageReference(package, true);
status_t error = package->Init(entry->d_name);
if (error != B_OK)
@ -454,7 +479,7 @@ Volume::_AddPackageDomain(PackageDomain* domain)
if (error != B_OK)
continue;
domain->AddPackage(packageDeleter.Detach());
domain->AddPackage(package);
}
// add the packages to the node tree
@ -602,7 +627,7 @@ Volume::_CreateNode(mode_t mode, Directory* parent, const char* name,
if (node == NULL)
RETURN_ERROR(B_NO_MEMORY);
ObjectDeleter<Node> nodeDeleter(node);
BReference<Node> nodeReference(node, true);
status_t error = node->Init(parent, name);
if (error != B_OK)
@ -611,8 +636,9 @@ Volume::_CreateNode(mode_t mode, Directory* parent, const char* name,
parent->AddChild(node);
fNodes.Insert(node);
nodeReference.Detach();
// we keep the initial node reference for this table
_node = nodeDeleter.Detach();
_node = node;
return B_OK;
}

View File

@ -523,6 +523,10 @@ packagefs_open_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie)
Directory* dir = dynamic_cast<Directory*>(node);
status_t error = check_access(dir, R_OK);
if (error != B_OK)
return error;
// create a cookie
NodeWriteLocker dirLocker(dir);
DirectoryCookie* cookie = new(std::nothrow) DirectoryCookie(dir);
@ -644,6 +648,361 @@ packagefs_rewind_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
}
// #pragma mark - Attribute Directories
struct AttributeDirectoryCookie {
Node* node;
PackageNode* packageNode;
PackageNodeAttribute* attribute;
AttributeDirectoryCookie(Node* node)
:
node(node),
packageNode(node->GetPackageNode()),
attribute(NULL)
{
if (packageNode != NULL) {
packageNode->AcquireReference();
attribute = packageNode->Attributes().Head();
}
}
~AttributeDirectoryCookie()
{
if (packageNode != NULL)
packageNode->ReleaseReference();
}
PackageNodeAttribute* Current() const
{
return attribute;
}
void Next()
{
if (attribute == NULL)
return;
attribute = packageNode->Attributes().GetNext(attribute);
}
void Rewind()
{
if (packageNode != NULL)
attribute = packageNode->Attributes().Head();
}
};
status_t
packagefs_open_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID());
status_t error = check_access(node, R_OK);
if (error != B_OK)
return error;
// create a cookie
NodeReadLocker nodeLocker(node);
AttributeDirectoryCookie* cookie
= new(std::nothrow) AttributeDirectoryCookie(node);
if (cookie == NULL)
RETURN_ERROR(B_NO_MEMORY);
*_cookie = cookie;
return B_OK;
}
status_t
packagefs_close_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
{
return B_OK;
}
status_t
packagefs_free_attr_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode,
void* _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
delete cookie;
return B_OK;
}
status_t
packagefs_read_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
struct dirent* buffer, size_t bufferSize, uint32* _count)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
uint32 maxCount = *_count;
uint32 count = 0;
dirent* previousEntry = NULL;
while (PackageNodeAttribute* attribute = cookie->Current()) {
// 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
const char* name = attribute->Name();
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 = node->ID();
count++;
previousEntry = buffer;
bufferSize -= buffer->d_reclen;
buffer = (dirent*)((addr_t)buffer + buffer->d_reclen);
cookie->Next();
}
*_count = count;
return B_OK;
}
status_t
packagefs_rewind_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
cookie->Rewind();
return B_OK;
}
// #pragma mark - Attribute Operations
struct AttributeCookie {
PackageNode* packageNode;
Package* package;
PackageNodeAttribute* attribute;
int openMode;
AttributeCookie(PackageNode* packageNode, PackageNodeAttribute* attribute,
int openMode)
:
packageNode(packageNode),
package(packageNode->GetPackage()),
attribute(attribute),
openMode(openMode)
{
packageNode->AcquireReference();
package->AcquireReference();
}
~AttributeCookie()
{
packageNode->ReleaseReference();
package->ReleaseReference();
}
};
status_t
packagefs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name,
int openMode, void** _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%lld), name: \"%s\", openMode %#x\n",
volume, node, node->ID(), name, openMode);
TOUCH(volume);
NodeReadLocker nodeLocker(node);
// check the open mode and permissions
if ((openMode & O_RWMASK) != O_RDONLY)
return B_NOT_ALLOWED;
status_t error = check_access(node, R_OK);
if (error != B_OK)
return error;
// get the package node and the respectively named attribute
PackageNode* packageNode = node->GetPackageNode();
PackageNodeAttribute* attribute = packageNode != NULL
? packageNode->FindAttribute(name) : NULL;
if (attribute == NULL)
return B_ENTRY_NOT_FOUND;
// allocate the cookie
AttributeCookie* cookie = new(std::nothrow) AttributeCookie(packageNode,
attribute, openMode);
if (cookie == NULL)
RETURN_ERROR(B_NO_MEMORY);
*_cookie = cookie;
return B_OK;
}
status_t
packagefs_close_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
{
return B_OK;
}
status_t
packagefs_free_attr_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
AttributeCookie* cookie = (AttributeCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
delete cookie;
return B_OK;
}
static status_t
read_package_data(const PackageData& data, DataReader* dataReader, off_t offset,
void* buffer, size_t* bufferSize)
{
// create a PackageDataReader
PackageDataReader* reader;
status_t error = GlobalFactory::Default()->CreatePackageDataReader(
dataReader, data, reader);
if (error != B_OK)
RETURN_ERROR(error);
ObjectDeleter<PackageDataReader> readerDeleter(reader);
// check the offset
if (offset < 0 || (uint64)offset > data.UncompressedSize())
return B_BAD_VALUE;
// clamp the size
size_t toRead = std::min((uint64)*bufferSize,
data.UncompressedSize() - offset);
// read
if (toRead > 0) {
status_t error = reader->ReadData(offset, buffer, toRead);
if (error != B_OK)
RETURN_ERROR(error);
}
*bufferSize = toRead;
return B_OK;
}
status_t
packagefs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
off_t offset, void* buffer, size_t* bufferSize)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
AttributeCookie* cookie = (AttributeCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
const PackageData& data = cookie->attribute->Data();
if (data.IsEncodedInline()) {
// inline data
BufferDataReader dataReader(data.InlineData(), data.CompressedSize());
return read_package_data(data, &dataReader, offset, buffer, bufferSize);
}
// data not inline -- open the package
int fd = cookie->package->Open();
if (fd < 0)
RETURN_ERROR(fd);
PackageCloser packageCloser(cookie->package);
FDDataReader dataReader(fd);
return read_package_data(data, &dataReader, offset, buffer, bufferSize);
}
status_t
packagefs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode,
void* _cookie, struct stat* st)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
AttributeCookie* cookie = (AttributeCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
st->st_size = cookie->attribute->Data().UncompressedSize();
st->st_type = cookie->attribute->Type();
return B_OK;
}
// #pragma mark - Module Interface
@ -717,13 +1076,13 @@ fs_volume_ops gPackageFSVolumeOps = {
fs_vnode_ops gPackageFSVnodeOps = {
/* vnode operations */
// vnode operations
&packagefs_lookup,
NULL, // get_vnode_name,
&packagefs_put_vnode,
&packagefs_put_vnode, // remove_vnode -- same as put_vnode
/* VM file access */
// VM file access
NULL, // can_page,
NULL, // read_pages,
NULL, // write_pages,
@ -750,7 +1109,7 @@ fs_vnode_ops gPackageFSVnodeOps = {
&packagefs_read_stat,
NULL, // write_stat,
/* file operations */
// file operations
NULL, // create,
&packagefs_open,
&packagefs_close,
@ -758,17 +1117,35 @@ fs_vnode_ops gPackageFSVnodeOps = {
&packagefs_read,
NULL, // write,
/* directory operations */
// directory operations
NULL, // create_dir,
NULL, // remove_dir,
&packagefs_open_dir,
&packagefs_close_dir,
&packagefs_free_dir_cookie,
&packagefs_read_dir,
&packagefs_rewind_dir
&packagefs_rewind_dir,
// attribute directory operations
&packagefs_open_attr_dir,
&packagefs_close_attr_dir,
&packagefs_free_attr_dir_cookie,
&packagefs_read_attr_dir,
&packagefs_rewind_attr_dir,
// attribute operations
NULL, // create_attr,
&packagefs_open_attr,
&packagefs_close_attr,
&packagefs_free_attr_cookie,
&packagefs_read_attr,
NULL, // write_attr,
&packagefs_read_attr_stat,
NULL, // write_attr_stat,
NULL, // rename_attr,
NULL // remove_attr,
// TODO: attribute directory operations
// TODO: attribute operations
// TODO: FS layer operations
};