diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Attribute.cpp b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Attribute.cpp index 01a5bb9692..75f74e4d58 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Attribute.cpp +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Attribute.cpp @@ -52,19 +52,30 @@ status_t Attribute::WriteAt(off_t offset, const void *buffer, size_t size, size_t *bytesWritten) { - status_t error = B_OK; - if (offset < kMaxIndexKeyLength && size > 0 && fIndex) { - // There is an index and a change will be made within the key. - uint8 oldKey[kMaxIndexKeyLength]; - size_t oldLength; - GetKey(oldKey, &oldLength); - error = DataContainer::WriteAt(offset, buffer, size, bytesWritten); + // get the current key for the attribute + uint8 oldKey[kMaxIndexKeyLength]; + size_t oldLength; + GetKey(oldKey, &oldLength); + + // write the new value + status_t error = DataContainer::WriteAt(offset, buffer, size, bytesWritten); + + // If there is an index and a change has been made within the key, notify + // the index. + if (offset < kMaxIndexKeyLength && size > 0 && fIndex) fIndex->Changed(this, oldKey, oldLength); - } else - error = DataContainer::WriteAt(offset, buffer, size, bytesWritten); + + // update live queries + const uint8* newKey; + size_t newLength; + GetKey(&newKey, &newLength); + GetVolume()->UpdateLiveQueries(NULL, fNode, GetName(), fType, oldKey, + oldLength, newKey, newLength); + // node has been changed - if (fNode) + if (fNode && size > 0) fNode->MarkModified(); + return error; } diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Directory.cpp b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Directory.cpp index 6e7138a7f6..b936bd6082 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Directory.cpp +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Directory.cpp @@ -156,17 +156,17 @@ Directory::CreateEntry(Node *node, const char *name, Entry **_entry) if (entry) { error = entry->InitCheck(); if (error == B_OK) { - // add the entry - error = AddEntry(entry); + // link to the node + error = entry->Link(node); if (error == B_OK) { - // link to the node - error = entry->Link(node); + // add the entry + error = AddEntry(entry); if (error == B_OK) { if (_entry) *_entry = entry; } else { - // failure: remove the entry - RemoveEntry(entry); + // failure: unlink the node + entry->Unlink(); } } } diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/LastModifiedIndex.cpp b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/LastModifiedIndex.cpp index e731a9e11b..72152b37c1 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/LastModifiedIndex.cpp +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/LastModifiedIndex.cpp @@ -157,9 +157,15 @@ LastModifiedIndex::Changed(Node *node, time_t oldModified) if (iterator->GetCurrentNode() == node) iterator->NodeRemoved(node); } - // remove the node + // remove and re-insert the node fNodes->Remove(it); error = fNodes->Insert(node); + + // udpate live queries + time_t newModified = node->GetMTime(); + fVolume->UpdateLiveQueries(NULL, node, GetName(), GetType(), + (const uint8*)&oldModified, sizeof(oldModified), + (const uint8*)&newModified, sizeof(newModified)); } } return error; diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/NameIndex.cpp b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/NameIndex.cpp index c84aeb1239..372db75f86 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/NameIndex.cpp +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/NameIndex.cpp @@ -139,6 +139,9 @@ NameIndex::Changed(Entry *entry, const char *oldName) if (foundEntry && *foundEntry == entry) { fEntries->Remove(it); error = fEntries->Insert(entry); + + // udpate live queries + _UpdateLiveQueries(entry, oldName, entry->GetName()); } } return error; @@ -148,16 +151,24 @@ NameIndex::Changed(Entry *entry, const char *oldName) void NameIndex::EntryAdded(Entry *entry) { - if (entry) + if (entry) { fEntries->Insert(entry); + + // udpate live queries + _UpdateLiveQueries(entry, NULL, entry->GetName()); + } } // EntryRemoved void NameIndex::EntryRemoved(Entry *entry) { - if (entry) + if (entry) { fEntries->Remove(entry, entry); + + // udpate live queries + _UpdateLiveQueries(entry, entry->GetName(), NULL); + } } // InternalGetIterator @@ -190,6 +201,16 @@ NameIndex::InternalFind(const uint8 *key, size_t length) return iterator; } +// _UpdateLiveQueries +void +NameIndex::_UpdateLiveQueries(Entry* entry, const char* oldName, + const char* newName) +{ + fVolume->UpdateLiveQueries(entry, entry->GetNode(), GetName(), + GetType(), (const uint8*)oldName, (oldName ? strlen(oldName) : 0), + (const uint8*)newName, (newName ? strlen(newName) : 0)); +} + // NameIndexEntryIterator diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/NameIndex.h b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/NameIndex.h index cecc79e974..3503b7c961 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/NameIndex.h +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/NameIndex.h @@ -32,6 +32,9 @@ private: class EntryTree; friend class NameIndexEntryIterator; + void _UpdateLiveQueries(Entry* entry, const char* oldName, + const char* newName); + private: EntryTree *fEntries; }; diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Query.cpp b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Query.cpp index 7f970a5b88..a1cea15070 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Query.cpp +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Query.cpp @@ -128,8 +128,6 @@ IndexIterator::GetNextEntry(uint8 *buffer, uint16 *_keyLength, } - - // compare_integral template static inline @@ -258,8 +256,9 @@ class Term { void SetParent(Term *parent) { fParent = parent; } Term *Parent() const { return fParent; } - virtual status_t Match(Entry *entry,const char *attribute = NULL,int32 type = 0, - const uint8 *key = NULL,size_t size = 0) = 0; + virtual status_t Match(Entry *entry, Node* node, + const char *attribute = NULL, int32 type = 0, + const uint8 *key = NULL, size_t size = 0) = 0; virtual void Complement() = 0; virtual void CalculateScore(IndexWrapper &index) = 0; @@ -267,6 +266,8 @@ class Term { virtual status_t InitCheck() = 0; + virtual bool NeedsEntry() = 0; + #ifdef DEBUG virtual void PrintToStream() = 0; #endif @@ -295,8 +296,9 @@ class Equation : public Term { status_t ParseQuotedString(char **_start, char **_end); char *CopyString(char *start, char *end); - virtual status_t Match(Entry *entry, const char *attribute = NULL, int32 type = 0, - const uint8 *key = NULL, size_t size = 0); + virtual status_t Match(Entry *entry, Node* node, + const char *attribute = NULL, int32 type = 0, + const uint8 *key = NULL, size_t size = 0); virtual void Complement(); status_t PrepareQuery(Volume *volume, IndexWrapper &index, IndexIterator **iterator, @@ -307,6 +309,8 @@ class Equation : public Term { virtual void CalculateScore(IndexWrapper &index); virtual int32 Score() const { return fScore; } + virtual bool NeedsEntry(); + #ifdef DEBUG virtual void PrintToStream(); #endif @@ -340,7 +344,8 @@ class Operator : public Term { Term *Left() const { return fLeft; } Term *Right() const { return fRight; } - virtual status_t Match(Entry *entry, const char *attribute = NULL, int32 type = 0, + virtual status_t Match(Entry *entry, Node* node, + const char *attribute = NULL, int32 type = 0, const uint8 *key = NULL, size_t size = 0); virtual void Complement(); @@ -349,6 +354,8 @@ class Operator : public Term { virtual status_t InitCheck(); + virtual bool NeedsEntry(); + //Term *Copy() const; #ifdef DEBUG virtual void PrintToStream(); @@ -940,7 +947,8 @@ Equation::MatchEmptyString() */ status_t -Equation::Match(Entry *entry, const char *attributeName, int32 type, const uint8 *key, size_t size) +Equation::Match(Entry *entry, Node* node, const char *attributeName, int32 type, + const uint8 *key, size_t size) { // get a pointer to the attribute in question union value value; @@ -949,14 +957,23 @@ Equation::Match(Entry *entry, const char *attributeName, int32 type, const uint8 // first, check if we are matching for a live query and use that value if (attributeName != NULL && !strcmp(fAttribute, attributeName)) { if (key == NULL) { - if (type == B_STRING_TYPE) + if (type == B_STRING_TYPE) { + // special case: a NULL "name" means the entry has been removed + // or not yet been added -- we refuse to match, whatever the + // pattern + if (!strcmp(fAttribute, "name")) + return NO_MATCH; + return MatchEmptyString(); + } return NO_MATCH; } buffer = const_cast(key); } else if (!strcmp(fAttribute, "name")) { // if not, check for "fake" attributes, "name", "size", "last_modified", + if (!entry) + return B_ERROR; buffer = (uint8 *)entry->GetName(); if (buffer == NULL) return B_ERROR; @@ -964,18 +981,18 @@ Equation::Match(Entry *entry, const char *attributeName, int32 type, const uint8 type = B_STRING_TYPE; size = strlen((const char *)buffer); } else if (!strcmp(fAttribute,"size")) { - value.Int64 = entry->GetNode()->GetSize(); + value.Int64 = node->GetSize(); buffer = (uint8 *)&value; type = B_INT64_TYPE; } else if (!strcmp(fAttribute,"last_modified")) { - value.Int32 = entry->GetNode()->GetMTime(); + value.Int32 = node->GetMTime(); buffer = (uint8 *)&value; type = B_INT32_TYPE; } else { // then for attributes Attribute *attribute = NULL; - if (entry->GetNode()->FindAttribute(fAttribute, &attribute) == B_OK) { + if (node->FindAttribute(fAttribute, &attribute) == B_OK) { attribute->GetKey(&buffer, &size); type = attribute->GetType(); } else @@ -1151,7 +1168,7 @@ Equation::GetNextMatching(Volume *volume, IndexIterator *iterator, status = MATCH_OK; if (!fHasIndex) - status = Match(entry); + status = Match(entry, entry->GetNode()); while (term != NULL && status == MATCH_OK) { Operator *parent = (Operator *)term->Parent(); @@ -1168,7 +1185,7 @@ Equation::GetNextMatching(Volume *volume, IndexIterator *iterator, FATAL(("&&-operator has only one child... (parent = %p)\n", parent)); break; } - status = other->Match(entry); + status = other->Match(entry, entry->GetNode()); if (status < 0) { REPORT_ERROR(status); status = NO_MATCH; @@ -1196,6 +1213,13 @@ Equation::GetNextMatching(Volume *volume, IndexIterator *iterator, } +bool +Equation::NeedsEntry() +{ + return strcmp(fAttribute, "name") == 0; +} + + // #pragma mark - @@ -1219,22 +1243,24 @@ Operator::~Operator() status_t -Operator::Match(Entry *entry, const char *attribute, int32 type, const uint8 *key, size_t size) +Operator::Match(Entry *entry, Node* node, const char *attribute, + int32 type, const uint8 *key, size_t size) { if (fOp == OP_AND) { - status_t status = fLeft->Match(entry, attribute, type, key, size); + status_t status = fLeft->Match(entry, node, attribute, type, key, size); if (status != MATCH_OK) return status; - return fRight->Match(entry, attribute, type, key, size); + return fRight->Match(entry, node, attribute, type, key, size); } else { // choose the term with the better score for OP_OR if (fRight->Score() > fLeft->Score()) { - status_t status = fRight->Match(entry, attribute, type, key, size); + status_t status = fRight->Match(entry, node, attribute, type, key, + size); if (status != NO_MATCH) return status; } - return fLeft->Match(entry, attribute, type, key, size); + return fLeft->Match(entry, node, attribute, type, key, size); } } @@ -1291,6 +1317,13 @@ Operator::InitCheck() } +bool +Operator::NeedsEntry() +{ + return ((fLeft && fLeft->NeedsEntry()) || (fRight && fRight->NeedsEntry())); +} + + #if 0 Term * Operator::Copy() const @@ -1529,7 +1562,8 @@ Query::Query(Volume *volume, Expression *expression, uint32 flags) fIterator(NULL), fIndex(volume), fFlags(flags), - fPort(-1) + fPort(-1), + fNeedsEntry(false) { // if the expression has a valid root pointer, the whole tree has // already passed the sanity check, so that we don't have to check @@ -1541,6 +1575,8 @@ Query::Query(Volume *volume, Expression *expression, uint32 flags) fExpression->Root()->CalculateScore(fIndex); fIndex.Unset(); + fNeedsEntry = fExpression->Root()->NeedsEntry(); + Rewind(); if (fFlags & B_LIVE_QUERY) @@ -1639,16 +1675,35 @@ Query::SetLiveMode(port_id port, int32 token) void -Query::LiveUpdate(Entry *entry, const char *attribute, int32 type, const uint8 *oldKey, - size_t oldLength, const uint8 *newKey, size_t newLength) +Query::LiveUpdate(Entry *entry, Node* node, const char *attribute, int32 type, + const uint8 *oldKey, size_t oldLength, const uint8 *newKey, + size_t newLength) { - if (fPort < 0 || fExpression == NULL || attribute == NULL) +PRINT(("%p->Query::LiveUpdate(%p, %p, \"%s\", 0x%lx, %p, %lu, %p, %lu)\n", +this, entry, node, attribute, type, oldKey, oldLength, newKey, newLength)); + if (fPort < 0 || fExpression == NULL || node == NULL || attribute == NULL) return; // ToDo: check if the attribute is part of the query at all... - status_t oldStatus = fExpression->Root()->Match(entry, attribute, type, oldKey, oldLength); - status_t newStatus = fExpression->Root()->Match(entry, attribute, type, newKey, newLength); + // If no entry has been supplied, but the we need one for the evaluation + // (i.e. the "name" attribute is used), we invoke ourselves for all entries + // referring to the given node. + if (!entry && fNeedsEntry) { + entry = node->GetFirstReferrer(); + while (entry) { + LiveUpdate(entry, node, attribute, type, oldKey, oldLength, newKey, + newLength); + entry = node->GetNextReferrer(entry); + } + return; + } + + status_t oldStatus = fExpression->Root()->Match(entry, node, attribute, + type, oldKey, oldLength); + status_t newStatus = fExpression->Root()->Match(entry, node, attribute, + type, newKey, newLength); +PRINT((" oldStatus: 0x%lx, newStatus: 0x%lx\n", oldStatus, newStatus)); int32 op; if (oldStatus == MATCH_OK && newStatus == MATCH_OK) { @@ -1656,8 +1711,14 @@ Query::LiveUpdate(Entry *entry, const char *attribute, int32 type, const uint8 * if (oldKey == NULL || strcmp(attribute,"name")) return; - send_notification(fPort, fToken, B_QUERY_UPDATE, B_ENTRY_REMOVED, fVolume->GetID(), 0, - entry->GetParent()->GetID(), 0, entry->GetNode()->GetID(), (const char *)oldKey); + if (entry) { + // entry should actually always be given, when the changed + // attribute is the entry name +PRINT(("send_notification(): old: B_ENTRY_REMOVED\n")); + send_notification(fPort, fToken, B_QUERY_UPDATE, B_ENTRY_REMOVED, + fVolume->GetID(), 0, entry->GetParent()->GetID(), 0, + entry->GetNode()->GetID(), (const char *)oldKey); + } op = B_ENTRY_CREATED; } else if (oldStatus != MATCH_OK && newStatus != MATCH_OK) { // nothing has changed @@ -1667,12 +1728,21 @@ Query::LiveUpdate(Entry *entry, const char *attribute, int32 type, const uint8 * else op = B_ENTRY_CREATED; - // if "value" is NULL, send_notification() crashes... - const char *value = (const char *)newKey; - if (type != B_STRING_TYPE || value == NULL) - value = ""; - - send_notification(fPort, fToken, B_QUERY_UPDATE, op, fVolume->GetID(), 0, - entry->GetParent()->GetID(), 0, entry->GetNode()->GetID(), value); + // We send a notification for the given entry, if any, or otherwise for + // all entries referring to the node; + if (entry) { +PRINT(("send_notification(): new: %s\n", (op == B_ENTRY_REMOVED ? "B_ENTRY_REMOVED" : "B_ENTRY_CREATED"))); + send_notification(fPort, fToken, B_QUERY_UPDATE, op, fVolume->GetID(), + 0, entry->GetParent()->GetID(), 0, entry->GetNode()->GetID(), + entry->GetName()); + } else { + entry = node->GetFirstReferrer(); + while (entry) { + send_notification(fPort, fToken, B_QUERY_UPDATE, op, + fVolume->GetID(), 0, entry->GetParent()->GetID(), 0, + entry->GetNode()->GetID(), entry->GetName()); + entry = node->GetNextReferrer(entry); + } + } } diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Query.h b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Query.h index 54b44ad45e..7d909d47f5 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Query.h +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Query.h @@ -12,6 +12,7 @@ #include #include +#include "DLList.h" #include "Index.h" #include "Stack.h" #include "ramfs.h" @@ -19,6 +20,7 @@ class Entry; class Equation; class IndexIterator; +class Node; class Query; class Term; class Volume; @@ -90,7 +92,7 @@ class Expression { Term *fTerm; }; -class Query { +class Query : public DLListLinkImpl { public: Query(Volume *volume, Expression *expression, uint32 flags); ~Query(); @@ -99,11 +101,15 @@ class Query { status_t GetNextEntry(struct dirent *, size_t size); void SetLiveMode(port_id port, int32 token); - void LiveUpdate(Entry *entry, const char *attribute, int32 type, - const uint8 *oldKey, size_t oldLength, const uint8 *newKey, size_t newLength); + void LiveUpdate(Entry *entry, Node* node, const char *attribute, + int32 type, const uint8 *oldKey, size_t oldLength, + const uint8 *newKey, size_t newLength); Expression *GetExpression() const { return fExpression; } + private: +// void SendNotification(Entry* entry) + private: Volume *fVolume; Expression *fExpression; @@ -115,6 +121,7 @@ class Query { uint32 fFlags; port_id fPort; int32 fToken; + bool fNeedsEntry; }; #endif /* QUERY_H */ diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/SizeIndex.cpp b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/SizeIndex.cpp index 13403f549d..f59068a5ce 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/SizeIndex.cpp +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/SizeIndex.cpp @@ -155,9 +155,16 @@ SizeIndex::Changed(Node *node, off_t oldSize) if (iterator->GetCurrentNode() == node) iterator->NodeRemoved(node); } - // remove the node + + // remove and re-insert the node fNodes->Remove(it); error = fNodes->Insert(node); + + // udpate live queries + off_t newSize = node->GetSize(); + fVolume->UpdateLiveQueries(NULL, node, GetName(), GetType(), + (const uint8*)&oldSize, sizeof(oldSize), (const uint8*)&newSize, + sizeof(newSize)); } } return error; diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Volume.cpp b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Volume.cpp index 038d4b14a3..996a446bf1 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Volume.cpp +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Volume.cpp @@ -33,6 +33,7 @@ #include "Entry.h" #include "EntryListener.h" #include "IndexDirectory.h" +#include "Locking.h" #include "Misc.h" #include "NameIndex.h" #include "Node.h" @@ -140,8 +141,9 @@ Volume::Volume() fIndexDirectory(NULL), fRootDirectory(NULL), fName(kDefaultVolumeName), - fLocker(), - fIteratorLocker(), + fLocker("volume"), + fIteratorLocker("iterators"), + fQueryLocker("queries"), fNodeListeners(NULL), fAnyNodeListeners(), fEntryListeners(NULL), @@ -165,6 +167,15 @@ status_t Volume::Mount(nspace_id id) { Unmount(); + + // check the locker's semaphores + if (fLocker.Sem() < 0) + return fLocker.Sem(); + if (fIteratorLocker.Sem() < 0) + return fIteratorLocker.Sem(); + if (fQueryLocker.Sem() < 0) + return fQueryLocker.Sem(); + status_t error = B_OK; fID = id; // create a block allocator @@ -659,6 +670,15 @@ Volume::NodeAttributeRemoved(vnode_id id, Attribute *attribute) index->Removed(attribute); } } + + // update live queries + if (error == B_OK && attribute->GetNode()) { + const uint8* oldKey; + size_t oldLength; + attribute->GetKey(&oldKey, &oldLength); + UpdateLiveQueries(NULL, attribute->GetNode(), attribute->GetName(), + attribute->GetType(), oldKey, oldLength, NULL, 0); + } } return error; } @@ -712,6 +732,42 @@ Volume::FindAttributeIndex(const char *name, uint32 type) ? fIndexDirectory->FindAttributeIndex(name, type) : NULL); } +// AddQuery +void +Volume::AddQuery(Query *query) +{ + AutoLocker _(fQueryLocker); + + if (query) + fQueries.Insert(query); +} + +// RemoveQuery +void +Volume::RemoveQuery(Query *query) +{ + AutoLocker _(fQueryLocker); + + if (query) + fQueries.Remove(query); +} + +// UpdateLiveQueries +void +Volume::UpdateLiveQueries(Entry *entry, Node* node, const char *attribute, + int32 type, const uint8 *oldKey, size_t oldLength, const uint8 *newKey, + size_t newLength) +{ + AutoLocker _(fQueryLocker); + + for (Query* query = fQueries.GetFirst(); + query; + query = fQueries.GetNext(query)) { + query->LiveUpdate(entry, node, attribute, type, oldKey, oldLength, + newKey, newLength); + } +} + // AllocateBlock status_t Volume::AllocateBlock(size_t size, BlockReference **block) diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Volume.h b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Volume.h index f78a325d7c..7e11712ea3 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Volume.h +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/Volume.h @@ -22,12 +22,14 @@ #ifndef VOLUME_H #define VOLUME_H +#include #include +#include "DLList.h" #include "Entry.h" -#include "fsproto.h" #include "List.h" #include "Locker.h" +#include "Query.h" #include "String.h" class AllocationInfo; @@ -48,7 +50,6 @@ class NodeAttributeTable; class NodeListener; class NodeListenerTree; class NodeTable; -class Query; class SizeIndex; const vnode_id kRootParentID = 0; @@ -146,11 +147,11 @@ public: AttributeIndex *FindAttributeIndex(const char *name, uint32 type); // queries -// TODO: Implement. -// status_t AddQuery(Query */*query*/) { return B_ERROR; } -// status_t RemoveQuery(Query */*query*/) { return B_ERROR; } - status_t AddQuery(Query */*query*/) { return B_OK; } - status_t RemoveQuery(Query */*query*/) { return B_OK; } + void AddQuery(Query *query); + void RemoveQuery(Query *query); + void UpdateLiveQueries(Entry *entry, Node* node, const char *attribute, + int32 type, const uint8 *oldKey, size_t oldLength, + const uint8 *newKey, size_t newLength); vnode_id NextNodeID() { return fNextNodeID++; } @@ -173,6 +174,8 @@ public: void IteratorUnlock(); private: + typedef DLList QueryList; + nspace_id fID; vnode_id fNextNodeID; NodeTable *fNodeTable; @@ -183,10 +186,12 @@ private: String fName; Locker fLocker; Locker fIteratorLocker; + Locker fQueryLocker; NodeListenerTree *fNodeListeners; NodeListenerList fAnyNodeListeners; EntryListenerTree *fEntryListeners; EntryListenerList fAnyEntryListeners; + QueryList fQueries; BlockAllocator *fBlockAllocator; off_t fBlockSize; off_t fAllocatedBlocks; diff --git a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/kernel_interface.cpp b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/kernel_interface.cpp index f68909d6b6..207a9973c0 100644 --- a/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/kernel_interface.cpp +++ b/src/tests/add-ons/kernel/file_systems/userlandfs/r5/src/test/ramfs/kernel_interface.cpp @@ -43,6 +43,7 @@ #include "AllocationInfo.h" #include "AttributeIndex.h" #include "AttributeIterator.h" +#include "AutoDeleter.h" #include "Debug.h" #include "Directory.h" #include "Entry.h" @@ -249,6 +250,10 @@ notify_if_stat_changed(Volume *volume, Node *node) } } + +// #pragma mark - FS + + // ramfs_mount static int @@ -323,6 +328,10 @@ ramfs_sync(void */*_ns*/) return B_OK; } + +// #pragma mark - VNodes + + // ramfs_read_vnode static int @@ -375,6 +384,10 @@ FUNCTION(("node: %Ld\n", ((Node*)_node)->GetID())); RETURN_ERROR(error); } + +// #pragma mark - Nodes + + // ramfs_walk static int @@ -562,6 +575,10 @@ ramfs_write_stat(void *ns, void *_node, struct stat *st, long mask) RETURN_ERROR(error); } + +// #pragma mark - Files + + // FileCookie class FileCookie { public: @@ -841,6 +858,11 @@ ramfs_access(void *ns, void *_node, int mode) RETURN_ERROR(error); } + + +// #pragma mark - Directories + + // ramfs_rename static int @@ -1330,7 +1352,11 @@ ramfs_free_dir_cookie(void */*ns*/, void */*_node*/, void *_cookie) delete cookie; return B_OK; } - + + +// #pragma mark - FS Stats + + // ramfs_read_fs_stat static int @@ -1354,6 +1380,7 @@ ramfs_read_fs_stat(void *ns, struct fs_info *info) return B_OK; } + // ramfs_write_fs_stat static int @@ -1370,6 +1397,10 @@ ramfs_write_fs_stat(void *ns, struct fs_info *info, long mask) RETURN_ERROR(error); } + +// #pragma mark - Symlinks + + // ramfs_symlink static int @@ -1455,6 +1486,10 @@ ramfs_read_link(void *ns, void *_node, char *buffer, size_t *bufferSize) RETURN_ERROR(error); } + +// #pragma mark - Attributes + + // ramfs_open_attrdir static int @@ -1703,6 +1738,10 @@ ramfs_stat_attr(void *ns, void *_node, const char *name, RETURN_ERROR(error); } + +// #pragma mark - Indices + + // IndexDirCookie class IndexDirCookie { public: @@ -1905,9 +1944,9 @@ ramfs_stat_index(void *ns, const char *name, struct index_info *indexInfo) } +// #pragma mark - Queries + // Query implementation by Axel Dörfler. Slightly adjusted. -// -// TODO: Locking! // ramfs_open_query int @@ -1922,21 +1961,30 @@ ramfs_open_query(void *ns, const char *queryString, ulong flags, port_id port, Volume *volume = (Volume *)ns; + // lock the volume + VolumeReadLocker locker(volume); + if (!locker.IsLocked()) + RETURN_ERROR(B_ERROR); + + // parse the query expression Expression *expression = new Expression((char *)queryString); if (expression == NULL) RETURN_ERROR(B_NO_MEMORY); + ObjectDeleter expressionDeleter(expression); if (expression->InitCheck() < B_OK) { - FATAL(("Could not parse query, stopped at: \"%s\"\n", expression->Position())); - delete expression; + WARN(("Could not parse query, stopped at: \"%s\"\n", + expression->Position())); RETURN_ERROR(B_BAD_VALUE); } + // create the query Query *query = new Query(volume, expression, flags); - if (query == NULL) { - delete expression; + if (query == NULL) RETURN_ERROR(B_NO_MEMORY); - } + expressionDeleter.Detach(); + // TODO: The Query references an Index, but nothing prevents the Index + // from being deleted, while the Query is in existence. if (flags & B_LIVE_QUERY) query->SetLiveMode(port, token); @@ -1956,12 +2004,19 @@ ramfs_close_query(void */*ns*/, void */*cookie*/) // ramfs_free_query_cookie int -ramfs_free_query_cookie(void */*ns*/, void */*node*/, void *cookie) +ramfs_free_query_cookie(void *ns, void */*node*/, void *cookie) { FUNCTION_START(); - if (cookie == NULL) + if (ns == NULL || cookie == NULL) RETURN_ERROR(B_BAD_VALUE); + Volume *volume = (Volume *)ns; + + // lock the volume + VolumeReadLocker locker(volume); + if (!locker.IsLocked()) + RETURN_ERROR(B_ERROR); + Query *query = (Query *)cookie; Expression *expression = query->GetExpression(); delete query; @@ -1972,14 +2027,21 @@ ramfs_free_query_cookie(void */*ns*/, void */*node*/, void *cookie) // ramfs_read_query int -ramfs_read_query(void */*ns*/, void *cookie, long *count, +ramfs_read_query(void *ns, void *cookie, long *count, struct dirent *buffer, size_t bufferSize) { FUNCTION_START(); Query *query = (Query *)cookie; - if (query == NULL) + if (ns == NULL || query == NULL) RETURN_ERROR(B_BAD_VALUE); + Volume *volume = (Volume *)ns; + + // lock the volume + VolumeReadLocker locker(volume); + if (!locker.IsLocked()) + RETURN_ERROR(B_ERROR); + status_t status = query->GetNextEntry(buffer, bufferSize); if (status == B_OK) *count = 1;