Add a global node listener mechanism
This commit is contained in:
@@ -18,6 +18,7 @@ HAIKU_PACKAGE_FS_SOURCES =
|
|||||||
GlobalFactory.cpp
|
GlobalFactory.cpp
|
||||||
kernel_interface.cpp
|
kernel_interface.cpp
|
||||||
Node.cpp
|
Node.cpp
|
||||||
|
NodeListener.cpp
|
||||||
Package.cpp
|
Package.cpp
|
||||||
PackageDirectory.cpp
|
PackageDirectory.cpp
|
||||||
PackageDomain.cpp
|
PackageDomain.cpp
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "NodeListener.h"
|
||||||
|
|
||||||
|
|
||||||
|
NodeListener::NodeListener()
|
||||||
|
:
|
||||||
|
fPrevious(this),
|
||||||
|
fNext(this),
|
||||||
|
fNode(NOT_LISTENING_NODE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NodeListener::~NodeListener()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
NodeListener::NodeAdded(Node* node)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
NodeListener::NodeRemoved(Node* node)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
NodeListener::NodeChanged(Node* node, uint32 statFields)
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef NODE_LISTENER_H
|
||||||
|
#define NODE_LISTENER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
#include <util/OpenHashTable.h>
|
||||||
|
|
||||||
|
|
||||||
|
class Node;
|
||||||
|
|
||||||
|
|
||||||
|
#define NOT_LISTENING_NODE ((Node*)~(addr_t)0)
|
||||||
|
|
||||||
|
|
||||||
|
class NodeListener {
|
||||||
|
public:
|
||||||
|
NodeListener();
|
||||||
|
virtual ~NodeListener();
|
||||||
|
|
||||||
|
virtual void NodeAdded(Node* node);
|
||||||
|
virtual void NodeRemoved(Node* node);
|
||||||
|
virtual void NodeChanged(Node* node, uint32 statFields);
|
||||||
|
|
||||||
|
void StartedListening(Node* node)
|
||||||
|
{ fNode = node; }
|
||||||
|
void StoppedListening()
|
||||||
|
{ fNode = NOT_LISTENING_NODE; }
|
||||||
|
bool IsListening() const
|
||||||
|
{ return fNode != NOT_LISTENING_NODE; }
|
||||||
|
Node* ListenedNode() const
|
||||||
|
{ return fNode; }
|
||||||
|
|
||||||
|
inline void AddNodeListener(NodeListener* listener);
|
||||||
|
inline NodeListener* RemoveNodeListener();
|
||||||
|
|
||||||
|
NodeListener* PreviousNodeListener() const
|
||||||
|
{ return fPrevious; }
|
||||||
|
NodeListener* NextNodeListener() const
|
||||||
|
{ return fNext; }
|
||||||
|
|
||||||
|
NodeListener*& NodeListenerHashLink()
|
||||||
|
{ return fHashLink; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
NodeListener* fHashLink;
|
||||||
|
NodeListener* fPrevious;
|
||||||
|
NodeListener* fNext;
|
||||||
|
Node* fNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline void
|
||||||
|
NodeListener::AddNodeListener(NodeListener* listener)
|
||||||
|
{
|
||||||
|
listener->fPrevious = this;
|
||||||
|
listener->fNext = fNext;
|
||||||
|
|
||||||
|
fNext->fPrevious = listener;
|
||||||
|
fNext = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline NodeListener*
|
||||||
|
NodeListener::RemoveNodeListener()
|
||||||
|
{
|
||||||
|
if (fNext == this)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
NodeListener* next = fNext;
|
||||||
|
|
||||||
|
fPrevious->fNext = next;
|
||||||
|
next->fPrevious = fPrevious;
|
||||||
|
|
||||||
|
fPrevious = fNext = this;
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct NodeListenerHashDefinition {
|
||||||
|
typedef Node* KeyType;
|
||||||
|
typedef NodeListener ValueType;
|
||||||
|
|
||||||
|
size_t HashKey(Node* key) const
|
||||||
|
{
|
||||||
|
return (size_t)key;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Hash(const NodeListener* value) const
|
||||||
|
{
|
||||||
|
return HashKey(value->ListenedNode());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compare(Node* key, const NodeListener* value) const
|
||||||
|
{
|
||||||
|
return key == value->ListenedNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeListener*& GetLink(NodeListener* value) const
|
||||||
|
{
|
||||||
|
return value->NodeListenerHashLink();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef DoublyLinkedList<NodeListener> NodeListenerList;
|
||||||
|
typedef BOpenHashTable<NodeListenerHashDefinition> NodeListenerHashTable;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NODE_LISTENER_H
|
||||||
@@ -52,6 +52,10 @@ using BPackageKit::BHPKG::BPrivate::PackageReaderImpl;
|
|||||||
// node ID of the root directory
|
// node ID of the root directory
|
||||||
static const ino_t kRootDirectoryID = 1;
|
static const ino_t kRootDirectoryID = 1;
|
||||||
|
|
||||||
|
static const uint32 kAllStatFields = B_STAT_MODE | B_STAT_UID | B_STAT_GID
|
||||||
|
| B_STAT_SIZE | B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME
|
||||||
|
| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME;
|
||||||
|
|
||||||
// shine-through directories
|
// shine-through directories
|
||||||
const char* const kSystemShineThroughDirectories[] = {
|
const char* const kSystemShineThroughDirectories[] = {
|
||||||
"packages", NULL
|
"packages", NULL
|
||||||
@@ -482,11 +486,16 @@ Volume::~Volume()
|
|||||||
status_t
|
status_t
|
||||||
Volume::Mount(const char* parameterString)
|
Volume::Mount(const char* parameterString)
|
||||||
{
|
{
|
||||||
// init the node table
|
// init the hash tables
|
||||||
status_t error = fNodes.Init();
|
status_t error = fNodes.Init();
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
error = fNodeListeners.Init();
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
// get the mount parameters
|
||||||
const char* packages = NULL;
|
const char* packages = NULL;
|
||||||
const char* volumeName = NULL;
|
const char* volumeName = NULL;
|
||||||
const char* mountType = NULL;
|
const char* mountType = NULL;
|
||||||
@@ -605,6 +614,42 @@ Volume::Unmount()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Volume::AddNodeListener(NodeListener* listener, Node* node)
|
||||||
|
{
|
||||||
|
ASSERT(!listener->IsListening());
|
||||||
|
|
||||||
|
listener->StartedListening(node);
|
||||||
|
|
||||||
|
if (NodeListener* list = fNodeListeners.Lookup(node))
|
||||||
|
list->AddNodeListener(listener);
|
||||||
|
else
|
||||||
|
fNodeListeners.Insert(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Volume::RemoveNodeListener(NodeListener* listener)
|
||||||
|
{
|
||||||
|
ASSERT(listener->IsListening());
|
||||||
|
|
||||||
|
Node* node = listener->ListenedNode();
|
||||||
|
|
||||||
|
if (NodeListener* next = listener->RemoveNodeListener()) {
|
||||||
|
// list not empty yet -- if we removed the head, add a new head to the
|
||||||
|
// hash table
|
||||||
|
NodeListener* list = fNodeListeners.Lookup(node);
|
||||||
|
if (list == listener) {
|
||||||
|
fNodeListeners.Remove(listener);
|
||||||
|
fNodeListeners.Insert(next);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
fNodeListeners.Remove(listener);
|
||||||
|
|
||||||
|
listener->StoppedListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Volume::GetVNode(ino_t nodeID, Node*& _node)
|
Volume::GetVNode(ino_t nodeID, Node*& _node)
|
||||||
{
|
{
|
||||||
@@ -662,6 +707,7 @@ Volume::PackageLinkNodeAdded(Node* node)
|
|||||||
_AddPackageLinksNode(node);
|
_AddPackageLinksNode(node);
|
||||||
|
|
||||||
notify_entry_created(ID(), node->Parent()->ID(), node->Name(), node->ID());
|
notify_entry_created(ID(), node->Parent()->ID(), node->Name(), node->ID());
|
||||||
|
_NotifyNodeAdded(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -671,6 +717,7 @@ Volume::PackageLinkNodeRemoved(Node* node)
|
|||||||
_RemovePackageLinksNode(node);
|
_RemovePackageLinksNode(node);
|
||||||
|
|
||||||
notify_entry_removed(ID(), node->Parent()->ID(), node->Name(), node->ID());
|
notify_entry_removed(ID(), node->Parent()->ID(), node->Name(), node->ID());
|
||||||
|
_NotifyNodeRemoved(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -678,6 +725,7 @@ void
|
|||||||
Volume::PackageLinkNodeChanged(Node* node, uint32 statFields)
|
Volume::PackageLinkNodeChanged(Node* node, uint32 statFields)
|
||||||
{
|
{
|
||||||
notify_stat_changed(ID(), node->ID(), statFields);
|
notify_stat_changed(ID(), node->ID(), statFields);
|
||||||
|
_NotifyNodeChanged(node, statFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1069,6 +1117,11 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
|
|||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (newNode)
|
||||||
|
_NotifyNodeAdded(node);
|
||||||
|
else
|
||||||
|
_NotifyNodeChanged(node, kAllStatFields);
|
||||||
|
|
||||||
if (notify) {
|
if (notify) {
|
||||||
if (newNode) {
|
if (newNode) {
|
||||||
notify_entry_created(ID(), directory->ID(), node->Name(),
|
notify_entry_created(ID(), directory->ID(), node->Name(),
|
||||||
@@ -1078,10 +1131,7 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
|
|||||||
// Send stat changed notification for directories and entry
|
// Send stat changed notification for directories and entry
|
||||||
// removed + created notifications for files and symlinks.
|
// removed + created notifications for files and symlinks.
|
||||||
if (S_ISDIR(packageNode->Mode())) {
|
if (S_ISDIR(packageNode->Mode())) {
|
||||||
notify_stat_changed(ID(), node->ID(),
|
notify_stat_changed(ID(), node->ID(), kAllStatFields);
|
||||||
B_STAT_MODE | B_STAT_UID | B_STAT_GID | B_STAT_SIZE
|
|
||||||
| B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME
|
|
||||||
| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME);
|
|
||||||
// TODO: Actually the attributes might change, too!
|
// TODO: Actually the attributes might change, too!
|
||||||
} else {
|
} else {
|
||||||
notify_entry_removed(ID(), directory->ID(), node->Name(),
|
notify_entry_removed(ID(), directory->ID(), node->Name(),
|
||||||
@@ -1133,6 +1183,11 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nodeRemoved)
|
||||||
|
_NotifyNodeRemoved(node);
|
||||||
|
else
|
||||||
|
_NotifyNodeChanged(node, kAllStatFields);
|
||||||
|
|
||||||
if (!notify)
|
if (!notify)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1144,10 +1199,7 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode,
|
|||||||
// Send stat changed notification for directories and entry
|
// Send stat changed notification for directories and entry
|
||||||
// removed + created notifications for files and symlinks.
|
// removed + created notifications for files and symlinks.
|
||||||
if (S_ISDIR(packageNode->Mode())) {
|
if (S_ISDIR(packageNode->Mode())) {
|
||||||
notify_stat_changed(ID(), node->ID(),
|
notify_stat_changed(ID(), node->ID(), kAllStatFields);
|
||||||
B_STAT_MODE | B_STAT_UID | B_STAT_GID | B_STAT_SIZE
|
|
||||||
| B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME
|
|
||||||
| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME);
|
|
||||||
// TODO: Actually the attributes might change, too!
|
// TODO: Actually the attributes might change, too!
|
||||||
} else {
|
} else {
|
||||||
notify_entry_removed(ID(), directory->ID(), node->Name(),
|
notify_entry_removed(ID(), directory->ID(), node->Name(),
|
||||||
@@ -1556,3 +1608,81 @@ Volume::_SystemVolumeIfNotSelf() const
|
|||||||
return systemVolume == this ? NULL : systemVolume;
|
return systemVolume == this ? NULL : systemVolume;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Volume::_NotifyNodeAdded(Node* node)
|
||||||
|
{
|
||||||
|
Node* key = node;
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
if (NodeListener* listener = fNodeListeners.Lookup(key)) {
|
||||||
|
NodeListener* last = listener->PreviousNodeListener();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
NodeListener* next = listener->NextNodeListener();
|
||||||
|
|
||||||
|
listener->NodeAdded(node);
|
||||||
|
|
||||||
|
if (listener == last)
|
||||||
|
break;
|
||||||
|
|
||||||
|
listener = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Volume::_NotifyNodeRemoved(Node* node)
|
||||||
|
{
|
||||||
|
Node* key = node;
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
if (NodeListener* listener = fNodeListeners.Lookup(key)) {
|
||||||
|
NodeListener* last = listener->PreviousNodeListener();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
NodeListener* next = listener->NextNodeListener();
|
||||||
|
|
||||||
|
listener->NodeRemoved(node);
|
||||||
|
|
||||||
|
if (listener == last)
|
||||||
|
break;
|
||||||
|
|
||||||
|
listener = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Volume::_NotifyNodeChanged(Node* node, uint32 statFields)
|
||||||
|
{
|
||||||
|
Node* key = node;
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
if (NodeListener* listener = fNodeListeners.Lookup(key)) {
|
||||||
|
NodeListener* last = listener->PreviousNodeListener();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
NodeListener* next = listener->NextNodeListener();
|
||||||
|
|
||||||
|
listener->NodeChanged(node, statFields);
|
||||||
|
|
||||||
|
if (listener == last)
|
||||||
|
break;
|
||||||
|
|
||||||
|
listener = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,12 +15,12 @@
|
|||||||
#include <util/KMessage.h>
|
#include <util/KMessage.h>
|
||||||
|
|
||||||
#include "Node.h"
|
#include "Node.h"
|
||||||
|
#include "NodeListener.h"
|
||||||
#include "PackageDomain.h"
|
#include "PackageDomain.h"
|
||||||
#include "PackageLinksListener.h"
|
#include "PackageLinksListener.h"
|
||||||
|
|
||||||
|
|
||||||
class Directory;
|
class Directory;
|
||||||
class Node;
|
|
||||||
class PackageFSRoot;
|
class PackageFSRoot;
|
||||||
class UnpackingNode;
|
class UnpackingNode;
|
||||||
|
|
||||||
@@ -66,6 +66,11 @@ public:
|
|||||||
Node* FindNode(ino_t nodeID) const
|
Node* FindNode(ino_t nodeID) const
|
||||||
{ return fNodes.Lookup(nodeID); }
|
{ return fNodes.Lookup(nodeID); }
|
||||||
|
|
||||||
|
// node listeners -- volume must be write-locked
|
||||||
|
void AddNodeListener(NodeListener* listener,
|
||||||
|
Node* node);
|
||||||
|
void RemoveNodeListener(NodeListener* listener);
|
||||||
|
|
||||||
// VFS wrappers
|
// VFS wrappers
|
||||||
status_t GetVNode(ino_t nodeID, Node*& _node);
|
status_t GetVNode(ino_t nodeID, Node*& _node);
|
||||||
status_t PutVNode(ino_t nodeID);
|
status_t PutVNode(ino_t nodeID);
|
||||||
@@ -162,6 +167,11 @@ private:
|
|||||||
|
|
||||||
inline Volume* _SystemVolumeIfNotSelf() const;
|
inline Volume* _SystemVolumeIfNotSelf() const;
|
||||||
|
|
||||||
|
void _NotifyNodeAdded(Node* node);
|
||||||
|
void _NotifyNodeRemoved(Node* node);
|
||||||
|
void _NotifyNodeChanged(Node* node,
|
||||||
|
uint32 statFields);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable rw_lock fLock;
|
mutable rw_lock fLock;
|
||||||
fs_volume* fFSVolume;
|
fs_volume* fFSVolume;
|
||||||
@@ -177,6 +187,7 @@ private:
|
|||||||
} fMountPoint;
|
} fMountPoint;
|
||||||
|
|
||||||
NodeIDHashTable fNodes;
|
NodeIDHashTable fNodes;
|
||||||
|
NodeListenerHashTable fNodeListeners;
|
||||||
|
|
||||||
JobList fJobQueue;
|
JobList fJobQueue;
|
||||||
mutex fJobQueueLock;
|
mutex fJobQueueLock;
|
||||||
|
|||||||
Reference in New Issue
Block a user