* Missing locking initialization in Volume::Mount().
* Added missing locking in the query hooks.
* Added live query support similarly as done in BFS:
- Volume manages a doubly-linked list of live queries.
- Volume::UpdateLiveQueries() invoked from several places where it makes
sense (standard indices, Attribute::WriteAt(), and
BVolume::NodeAttributeRemoved()) notifies the live Query objects.
- Adjusted Query to be able to deal with hard links. Unfortunately Tracker
is a bit broken with respect to hard links, particularly in the query
windows. E.g. only one entry referring to a node is shown, and the renaming
method RamFS uses (link new entry, then unlink old one) causes renamed
entries to fall out of queries, even if they should still be in.
(Want a bug report for this, Axel? :-P)
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20203 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -52,19 +52,30 @@ status_t
|
|||||||
Attribute::WriteAt(off_t offset, const void *buffer, size_t size,
|
Attribute::WriteAt(off_t offset, const void *buffer, size_t size,
|
||||||
size_t *bytesWritten)
|
size_t *bytesWritten)
|
||||||
{
|
{
|
||||||
status_t error = B_OK;
|
// get the current key for the attribute
|
||||||
if (offset < kMaxIndexKeyLength && size > 0 && fIndex) {
|
uint8 oldKey[kMaxIndexKeyLength];
|
||||||
// There is an index and a change will be made within the key.
|
size_t oldLength;
|
||||||
uint8 oldKey[kMaxIndexKeyLength];
|
GetKey(oldKey, &oldLength);
|
||||||
size_t oldLength;
|
|
||||||
GetKey(oldKey, &oldLength);
|
// write the new value
|
||||||
error = DataContainer::WriteAt(offset, buffer, size, bytesWritten);
|
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);
|
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
|
// node has been changed
|
||||||
if (fNode)
|
if (fNode && size > 0)
|
||||||
fNode->MarkModified();
|
fNode->MarkModified();
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -156,17 +156,17 @@ Directory::CreateEntry(Node *node, const char *name, Entry **_entry)
|
|||||||
if (entry) {
|
if (entry) {
|
||||||
error = entry->InitCheck();
|
error = entry->InitCheck();
|
||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
// add the entry
|
// link to the node
|
||||||
error = AddEntry(entry);
|
error = entry->Link(node);
|
||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
// link to the node
|
// add the entry
|
||||||
error = entry->Link(node);
|
error = AddEntry(entry);
|
||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
if (_entry)
|
if (_entry)
|
||||||
*_entry = entry;
|
*_entry = entry;
|
||||||
} else {
|
} else {
|
||||||
// failure: remove the entry
|
// failure: unlink the node
|
||||||
RemoveEntry(entry);
|
entry->Unlink();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -157,9 +157,15 @@ LastModifiedIndex::Changed(Node *node, time_t oldModified)
|
|||||||
if (iterator->GetCurrentNode() == node)
|
if (iterator->GetCurrentNode() == node)
|
||||||
iterator->NodeRemoved(node);
|
iterator->NodeRemoved(node);
|
||||||
}
|
}
|
||||||
// remove the node
|
// remove and re-insert the node
|
||||||
fNodes->Remove(it);
|
fNodes->Remove(it);
|
||||||
error = fNodes->Insert(node);
|
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;
|
return error;
|
||||||
|
|||||||
@@ -139,6 +139,9 @@ NameIndex::Changed(Entry *entry, const char *oldName)
|
|||||||
if (foundEntry && *foundEntry == entry) {
|
if (foundEntry && *foundEntry == entry) {
|
||||||
fEntries->Remove(it);
|
fEntries->Remove(it);
|
||||||
error = fEntries->Insert(entry);
|
error = fEntries->Insert(entry);
|
||||||
|
|
||||||
|
// udpate live queries
|
||||||
|
_UpdateLiveQueries(entry, oldName, entry->GetName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
@@ -148,16 +151,24 @@ NameIndex::Changed(Entry *entry, const char *oldName)
|
|||||||
void
|
void
|
||||||
NameIndex::EntryAdded(Entry *entry)
|
NameIndex::EntryAdded(Entry *entry)
|
||||||
{
|
{
|
||||||
if (entry)
|
if (entry) {
|
||||||
fEntries->Insert(entry);
|
fEntries->Insert(entry);
|
||||||
|
|
||||||
|
// udpate live queries
|
||||||
|
_UpdateLiveQueries(entry, NULL, entry->GetName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EntryRemoved
|
// EntryRemoved
|
||||||
void
|
void
|
||||||
NameIndex::EntryRemoved(Entry *entry)
|
NameIndex::EntryRemoved(Entry *entry)
|
||||||
{
|
{
|
||||||
if (entry)
|
if (entry) {
|
||||||
fEntries->Remove(entry, entry);
|
fEntries->Remove(entry, entry);
|
||||||
|
|
||||||
|
// udpate live queries
|
||||||
|
_UpdateLiveQueries(entry, entry->GetName(), NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InternalGetIterator
|
// InternalGetIterator
|
||||||
@@ -190,6 +201,16 @@ NameIndex::InternalFind(const uint8 *key, size_t length)
|
|||||||
return iterator;
|
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
|
// NameIndexEntryIterator
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ private:
|
|||||||
class EntryTree;
|
class EntryTree;
|
||||||
friend class NameIndexEntryIterator;
|
friend class NameIndexEntryIterator;
|
||||||
|
|
||||||
|
void _UpdateLiveQueries(Entry* entry, const char* oldName,
|
||||||
|
const char* newName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EntryTree *fEntries;
|
EntryTree *fEntries;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -128,8 +128,6 @@ IndexIterator::GetNextEntry(uint8 *buffer, uint16 *_keyLength,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// compare_integral
|
// compare_integral
|
||||||
template<typename Key>
|
template<typename Key>
|
||||||
static inline
|
static inline
|
||||||
@@ -258,8 +256,9 @@ class Term {
|
|||||||
void SetParent(Term *parent) { fParent = parent; }
|
void SetParent(Term *parent) { fParent = parent; }
|
||||||
Term *Parent() const { return fParent; }
|
Term *Parent() const { return fParent; }
|
||||||
|
|
||||||
virtual status_t Match(Entry *entry,const char *attribute = NULL,int32 type = 0,
|
virtual status_t Match(Entry *entry, Node* node,
|
||||||
const uint8 *key = NULL,size_t size = 0) = 0;
|
const char *attribute = NULL, int32 type = 0,
|
||||||
|
const uint8 *key = NULL, size_t size = 0) = 0;
|
||||||
virtual void Complement() = 0;
|
virtual void Complement() = 0;
|
||||||
|
|
||||||
virtual void CalculateScore(IndexWrapper &index) = 0;
|
virtual void CalculateScore(IndexWrapper &index) = 0;
|
||||||
@@ -267,6 +266,8 @@ class Term {
|
|||||||
|
|
||||||
virtual status_t InitCheck() = 0;
|
virtual status_t InitCheck() = 0;
|
||||||
|
|
||||||
|
virtual bool NeedsEntry() = 0;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
virtual void PrintToStream() = 0;
|
virtual void PrintToStream() = 0;
|
||||||
#endif
|
#endif
|
||||||
@@ -295,8 +296,9 @@ class Equation : public Term {
|
|||||||
status_t ParseQuotedString(char **_start, char **_end);
|
status_t ParseQuotedString(char **_start, char **_end);
|
||||||
char *CopyString(char *start, char *end);
|
char *CopyString(char *start, char *end);
|
||||||
|
|
||||||
virtual status_t Match(Entry *entry, const char *attribute = NULL, int32 type = 0,
|
virtual status_t Match(Entry *entry, Node* node,
|
||||||
const uint8 *key = NULL, size_t size = 0);
|
const char *attribute = NULL, int32 type = 0,
|
||||||
|
const uint8 *key = NULL, size_t size = 0);
|
||||||
virtual void Complement();
|
virtual void Complement();
|
||||||
|
|
||||||
status_t PrepareQuery(Volume *volume, IndexWrapper &index, IndexIterator **iterator,
|
status_t PrepareQuery(Volume *volume, IndexWrapper &index, IndexIterator **iterator,
|
||||||
@@ -307,6 +309,8 @@ class Equation : public Term {
|
|||||||
virtual void CalculateScore(IndexWrapper &index);
|
virtual void CalculateScore(IndexWrapper &index);
|
||||||
virtual int32 Score() const { return fScore; }
|
virtual int32 Score() const { return fScore; }
|
||||||
|
|
||||||
|
virtual bool NeedsEntry();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
virtual void PrintToStream();
|
virtual void PrintToStream();
|
||||||
#endif
|
#endif
|
||||||
@@ -340,7 +344,8 @@ class Operator : public Term {
|
|||||||
Term *Left() const { return fLeft; }
|
Term *Left() const { return fLeft; }
|
||||||
Term *Right() const { return fRight; }
|
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);
|
const uint8 *key = NULL, size_t size = 0);
|
||||||
virtual void Complement();
|
virtual void Complement();
|
||||||
|
|
||||||
@@ -349,6 +354,8 @@ class Operator : public Term {
|
|||||||
|
|
||||||
virtual status_t InitCheck();
|
virtual status_t InitCheck();
|
||||||
|
|
||||||
|
virtual bool NeedsEntry();
|
||||||
|
|
||||||
//Term *Copy() const;
|
//Term *Copy() const;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
virtual void PrintToStream();
|
virtual void PrintToStream();
|
||||||
@@ -940,7 +947,8 @@ Equation::MatchEmptyString()
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
status_t
|
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
|
// get a pointer to the attribute in question
|
||||||
union value value;
|
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
|
// first, check if we are matching for a live query and use that value
|
||||||
if (attributeName != NULL && !strcmp(fAttribute, attributeName)) {
|
if (attributeName != NULL && !strcmp(fAttribute, attributeName)) {
|
||||||
if (key == NULL) {
|
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 MatchEmptyString();
|
||||||
|
}
|
||||||
|
|
||||||
return NO_MATCH;
|
return NO_MATCH;
|
||||||
}
|
}
|
||||||
buffer = const_cast<uint8 *>(key);
|
buffer = const_cast<uint8 *>(key);
|
||||||
} else if (!strcmp(fAttribute, "name")) {
|
} else if (!strcmp(fAttribute, "name")) {
|
||||||
// if not, check for "fake" attributes, "name", "size", "last_modified",
|
// if not, check for "fake" attributes, "name", "size", "last_modified",
|
||||||
|
if (!entry)
|
||||||
|
return B_ERROR;
|
||||||
buffer = (uint8 *)entry->GetName();
|
buffer = (uint8 *)entry->GetName();
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
@@ -964,18 +981,18 @@ Equation::Match(Entry *entry, const char *attributeName, int32 type, const uint8
|
|||||||
type = B_STRING_TYPE;
|
type = B_STRING_TYPE;
|
||||||
size = strlen((const char *)buffer);
|
size = strlen((const char *)buffer);
|
||||||
} else if (!strcmp(fAttribute,"size")) {
|
} else if (!strcmp(fAttribute,"size")) {
|
||||||
value.Int64 = entry->GetNode()->GetSize();
|
value.Int64 = node->GetSize();
|
||||||
buffer = (uint8 *)&value;
|
buffer = (uint8 *)&value;
|
||||||
type = B_INT64_TYPE;
|
type = B_INT64_TYPE;
|
||||||
} else if (!strcmp(fAttribute,"last_modified")) {
|
} else if (!strcmp(fAttribute,"last_modified")) {
|
||||||
value.Int32 = entry->GetNode()->GetMTime();
|
value.Int32 = node->GetMTime();
|
||||||
buffer = (uint8 *)&value;
|
buffer = (uint8 *)&value;
|
||||||
type = B_INT32_TYPE;
|
type = B_INT32_TYPE;
|
||||||
} else {
|
} else {
|
||||||
// then for attributes
|
// then for attributes
|
||||||
Attribute *attribute = NULL;
|
Attribute *attribute = NULL;
|
||||||
|
|
||||||
if (entry->GetNode()->FindAttribute(fAttribute, &attribute) == B_OK) {
|
if (node->FindAttribute(fAttribute, &attribute) == B_OK) {
|
||||||
attribute->GetKey(&buffer, &size);
|
attribute->GetKey(&buffer, &size);
|
||||||
type = attribute->GetType();
|
type = attribute->GetType();
|
||||||
} else
|
} else
|
||||||
@@ -1151,7 +1168,7 @@ Equation::GetNextMatching(Volume *volume, IndexIterator *iterator,
|
|||||||
status = MATCH_OK;
|
status = MATCH_OK;
|
||||||
|
|
||||||
if (!fHasIndex)
|
if (!fHasIndex)
|
||||||
status = Match(entry);
|
status = Match(entry, entry->GetNode());
|
||||||
|
|
||||||
while (term != NULL && status == MATCH_OK) {
|
while (term != NULL && status == MATCH_OK) {
|
||||||
Operator *parent = (Operator *)term->Parent();
|
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));
|
FATAL(("&&-operator has only one child... (parent = %p)\n", parent));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
status = other->Match(entry);
|
status = other->Match(entry, entry->GetNode());
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
REPORT_ERROR(status);
|
REPORT_ERROR(status);
|
||||||
status = NO_MATCH;
|
status = NO_MATCH;
|
||||||
@@ -1196,6 +1213,13 @@ Equation::GetNextMatching(Volume *volume, IndexIterator *iterator,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Equation::NeedsEntry()
|
||||||
|
{
|
||||||
|
return strcmp(fAttribute, "name") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -1219,22 +1243,24 @@ Operator::~Operator()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
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) {
|
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)
|
if (status != MATCH_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
return fRight->Match(entry, attribute, type, key, size);
|
return fRight->Match(entry, node, attribute, type, key, size);
|
||||||
} else {
|
} else {
|
||||||
// choose the term with the better score for OP_OR
|
// choose the term with the better score for OP_OR
|
||||||
if (fRight->Score() > fLeft->Score()) {
|
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)
|
if (status != NO_MATCH)
|
||||||
return status;
|
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
|
#if 0
|
||||||
Term *
|
Term *
|
||||||
Operator::Copy() const
|
Operator::Copy() const
|
||||||
@@ -1529,7 +1562,8 @@ Query::Query(Volume *volume, Expression *expression, uint32 flags)
|
|||||||
fIterator(NULL),
|
fIterator(NULL),
|
||||||
fIndex(volume),
|
fIndex(volume),
|
||||||
fFlags(flags),
|
fFlags(flags),
|
||||||
fPort(-1)
|
fPort(-1),
|
||||||
|
fNeedsEntry(false)
|
||||||
{
|
{
|
||||||
// if the expression has a valid root pointer, the whole tree has
|
// 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
|
// 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);
|
fExpression->Root()->CalculateScore(fIndex);
|
||||||
fIndex.Unset();
|
fIndex.Unset();
|
||||||
|
|
||||||
|
fNeedsEntry = fExpression->Root()->NeedsEntry();
|
||||||
|
|
||||||
Rewind();
|
Rewind();
|
||||||
|
|
||||||
if (fFlags & B_LIVE_QUERY)
|
if (fFlags & B_LIVE_QUERY)
|
||||||
@@ -1639,16 +1675,35 @@ Query::SetLiveMode(port_id port, int32 token)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Query::LiveUpdate(Entry *entry, const char *attribute, int32 type, const uint8 *oldKey,
|
Query::LiveUpdate(Entry *entry, Node* node, const char *attribute, int32 type,
|
||||||
size_t oldLength, const uint8 *newKey, size_t newLength)
|
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;
|
return;
|
||||||
|
|
||||||
// ToDo: check if the attribute is part of the query at all...
|
// ToDo: check if the attribute is part of the query at all...
|
||||||
|
|
||||||
status_t oldStatus = fExpression->Root()->Match(entry, attribute, type, oldKey, oldLength);
|
// If no entry has been supplied, but the we need one for the evaluation
|
||||||
status_t newStatus = fExpression->Root()->Match(entry, attribute, type, newKey, newLength);
|
// (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;
|
int32 op;
|
||||||
if (oldStatus == MATCH_OK && newStatus == MATCH_OK) {
|
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"))
|
if (oldKey == NULL || strcmp(attribute,"name"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
send_notification(fPort, fToken, B_QUERY_UPDATE, B_ENTRY_REMOVED, fVolume->GetID(), 0,
|
if (entry) {
|
||||||
entry->GetParent()->GetID(), 0, entry->GetNode()->GetID(), (const char *)oldKey);
|
// 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;
|
op = B_ENTRY_CREATED;
|
||||||
} else if (oldStatus != MATCH_OK && newStatus != MATCH_OK) {
|
} else if (oldStatus != MATCH_OK && newStatus != MATCH_OK) {
|
||||||
// nothing has changed
|
// nothing has changed
|
||||||
@@ -1667,12 +1728,21 @@ Query::LiveUpdate(Entry *entry, const char *attribute, int32 type, const uint8 *
|
|||||||
else
|
else
|
||||||
op = B_ENTRY_CREATED;
|
op = B_ENTRY_CREATED;
|
||||||
|
|
||||||
// if "value" is NULL, send_notification() crashes...
|
// We send a notification for the given entry, if any, or otherwise for
|
||||||
const char *value = (const char *)newKey;
|
// all entries referring to the node;
|
||||||
if (type != B_STRING_TYPE || value == NULL)
|
if (entry) {
|
||||||
value = "";
|
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(),
|
||||||
send_notification(fPort, fToken, B_QUERY_UPDATE, op, fVolume->GetID(), 0,
|
0, entry->GetParent()->GetID(), 0, entry->GetNode()->GetID(),
|
||||||
entry->GetParent()->GetID(), 0, entry->GetNode()->GetID(), value);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
#include <SupportDefs.h>
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
#include "DLList.h"
|
||||||
#include "Index.h"
|
#include "Index.h"
|
||||||
#include "Stack.h"
|
#include "Stack.h"
|
||||||
#include "ramfs.h"
|
#include "ramfs.h"
|
||||||
@@ -19,6 +20,7 @@
|
|||||||
class Entry;
|
class Entry;
|
||||||
class Equation;
|
class Equation;
|
||||||
class IndexIterator;
|
class IndexIterator;
|
||||||
|
class Node;
|
||||||
class Query;
|
class Query;
|
||||||
class Term;
|
class Term;
|
||||||
class Volume;
|
class Volume;
|
||||||
@@ -90,7 +92,7 @@ class Expression {
|
|||||||
Term *fTerm;
|
Term *fTerm;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Query {
|
class Query : public DLListLinkImpl<Query> {
|
||||||
public:
|
public:
|
||||||
Query(Volume *volume, Expression *expression, uint32 flags);
|
Query(Volume *volume, Expression *expression, uint32 flags);
|
||||||
~Query();
|
~Query();
|
||||||
@@ -99,11 +101,15 @@ class Query {
|
|||||||
status_t GetNextEntry(struct dirent *, size_t size);
|
status_t GetNextEntry(struct dirent *, size_t size);
|
||||||
|
|
||||||
void SetLiveMode(port_id port, int32 token);
|
void SetLiveMode(port_id port, int32 token);
|
||||||
void LiveUpdate(Entry *entry, const char *attribute, int32 type,
|
void LiveUpdate(Entry *entry, Node* node, const char *attribute,
|
||||||
const uint8 *oldKey, size_t oldLength, const uint8 *newKey, size_t newLength);
|
int32 type, const uint8 *oldKey, size_t oldLength,
|
||||||
|
const uint8 *newKey, size_t newLength);
|
||||||
|
|
||||||
Expression *GetExpression() const { return fExpression; }
|
Expression *GetExpression() const { return fExpression; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// void SendNotification(Entry* entry)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Volume *fVolume;
|
Volume *fVolume;
|
||||||
Expression *fExpression;
|
Expression *fExpression;
|
||||||
@@ -115,6 +121,7 @@ class Query {
|
|||||||
uint32 fFlags;
|
uint32 fFlags;
|
||||||
port_id fPort;
|
port_id fPort;
|
||||||
int32 fToken;
|
int32 fToken;
|
||||||
|
bool fNeedsEntry;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* QUERY_H */
|
#endif /* QUERY_H */
|
||||||
|
|||||||
@@ -155,9 +155,16 @@ SizeIndex::Changed(Node *node, off_t oldSize)
|
|||||||
if (iterator->GetCurrentNode() == node)
|
if (iterator->GetCurrentNode() == node)
|
||||||
iterator->NodeRemoved(node);
|
iterator->NodeRemoved(node);
|
||||||
}
|
}
|
||||||
// remove the node
|
|
||||||
|
// remove and re-insert the node
|
||||||
fNodes->Remove(it);
|
fNodes->Remove(it);
|
||||||
error = fNodes->Insert(node);
|
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;
|
return error;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "Entry.h"
|
#include "Entry.h"
|
||||||
#include "EntryListener.h"
|
#include "EntryListener.h"
|
||||||
#include "IndexDirectory.h"
|
#include "IndexDirectory.h"
|
||||||
|
#include "Locking.h"
|
||||||
#include "Misc.h"
|
#include "Misc.h"
|
||||||
#include "NameIndex.h"
|
#include "NameIndex.h"
|
||||||
#include "Node.h"
|
#include "Node.h"
|
||||||
@@ -140,8 +141,9 @@ Volume::Volume()
|
|||||||
fIndexDirectory(NULL),
|
fIndexDirectory(NULL),
|
||||||
fRootDirectory(NULL),
|
fRootDirectory(NULL),
|
||||||
fName(kDefaultVolumeName),
|
fName(kDefaultVolumeName),
|
||||||
fLocker(),
|
fLocker("volume"),
|
||||||
fIteratorLocker(),
|
fIteratorLocker("iterators"),
|
||||||
|
fQueryLocker("queries"),
|
||||||
fNodeListeners(NULL),
|
fNodeListeners(NULL),
|
||||||
fAnyNodeListeners(),
|
fAnyNodeListeners(),
|
||||||
fEntryListeners(NULL),
|
fEntryListeners(NULL),
|
||||||
@@ -165,6 +167,15 @@ status_t
|
|||||||
Volume::Mount(nspace_id id)
|
Volume::Mount(nspace_id id)
|
||||||
{
|
{
|
||||||
Unmount();
|
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;
|
status_t error = B_OK;
|
||||||
fID = id;
|
fID = id;
|
||||||
// create a block allocator
|
// create a block allocator
|
||||||
@@ -659,6 +670,15 @@ Volume::NodeAttributeRemoved(vnode_id id, Attribute *attribute)
|
|||||||
index->Removed(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;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -712,6 +732,42 @@ Volume::FindAttributeIndex(const char *name, uint32 type)
|
|||||||
? fIndexDirectory->FindAttributeIndex(name, type) : NULL);
|
? fIndexDirectory->FindAttributeIndex(name, type) : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddQuery
|
||||||
|
void
|
||||||
|
Volume::AddQuery(Query *query)
|
||||||
|
{
|
||||||
|
AutoLocker<Locker> _(fQueryLocker);
|
||||||
|
|
||||||
|
if (query)
|
||||||
|
fQueries.Insert(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveQuery
|
||||||
|
void
|
||||||
|
Volume::RemoveQuery(Query *query)
|
||||||
|
{
|
||||||
|
AutoLocker<Locker> _(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<Locker> _(fQueryLocker);
|
||||||
|
|
||||||
|
for (Query* query = fQueries.GetFirst();
|
||||||
|
query;
|
||||||
|
query = fQueries.GetNext(query)) {
|
||||||
|
query->LiveUpdate(entry, node, attribute, type, oldKey, oldLength,
|
||||||
|
newKey, newLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AllocateBlock
|
// AllocateBlock
|
||||||
status_t
|
status_t
|
||||||
Volume::AllocateBlock(size_t size, BlockReference **block)
|
Volume::AllocateBlock(size_t size, BlockReference **block)
|
||||||
|
|||||||
@@ -22,12 +22,14 @@
|
|||||||
#ifndef VOLUME_H
|
#ifndef VOLUME_H
|
||||||
#define VOLUME_H
|
#define VOLUME_H
|
||||||
|
|
||||||
|
#include <fsproto.h>
|
||||||
#include <SupportDefs.h>
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
#include "DLList.h"
|
||||||
#include "Entry.h"
|
#include "Entry.h"
|
||||||
#include "fsproto.h"
|
|
||||||
#include "List.h"
|
#include "List.h"
|
||||||
#include "Locker.h"
|
#include "Locker.h"
|
||||||
|
#include "Query.h"
|
||||||
#include "String.h"
|
#include "String.h"
|
||||||
|
|
||||||
class AllocationInfo;
|
class AllocationInfo;
|
||||||
@@ -48,7 +50,6 @@ class NodeAttributeTable;
|
|||||||
class NodeListener;
|
class NodeListener;
|
||||||
class NodeListenerTree;
|
class NodeListenerTree;
|
||||||
class NodeTable;
|
class NodeTable;
|
||||||
class Query;
|
|
||||||
class SizeIndex;
|
class SizeIndex;
|
||||||
|
|
||||||
const vnode_id kRootParentID = 0;
|
const vnode_id kRootParentID = 0;
|
||||||
@@ -146,11 +147,11 @@ public:
|
|||||||
AttributeIndex *FindAttributeIndex(const char *name, uint32 type);
|
AttributeIndex *FindAttributeIndex(const char *name, uint32 type);
|
||||||
|
|
||||||
// queries
|
// queries
|
||||||
// TODO: Implement.
|
void AddQuery(Query *query);
|
||||||
// status_t AddQuery(Query */*query*/) { return B_ERROR; }
|
void RemoveQuery(Query *query);
|
||||||
// status_t RemoveQuery(Query */*query*/) { return B_ERROR; }
|
void UpdateLiveQueries(Entry *entry, Node* node, const char *attribute,
|
||||||
status_t AddQuery(Query */*query*/) { return B_OK; }
|
int32 type, const uint8 *oldKey, size_t oldLength,
|
||||||
status_t RemoveQuery(Query */*query*/) { return B_OK; }
|
const uint8 *newKey, size_t newLength);
|
||||||
|
|
||||||
vnode_id NextNodeID() { return fNextNodeID++; }
|
vnode_id NextNodeID() { return fNextNodeID++; }
|
||||||
|
|
||||||
@@ -173,6 +174,8 @@ public:
|
|||||||
void IteratorUnlock();
|
void IteratorUnlock();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typedef DLList<Query> QueryList;
|
||||||
|
|
||||||
nspace_id fID;
|
nspace_id fID;
|
||||||
vnode_id fNextNodeID;
|
vnode_id fNextNodeID;
|
||||||
NodeTable *fNodeTable;
|
NodeTable *fNodeTable;
|
||||||
@@ -183,10 +186,12 @@ private:
|
|||||||
String fName;
|
String fName;
|
||||||
Locker fLocker;
|
Locker fLocker;
|
||||||
Locker fIteratorLocker;
|
Locker fIteratorLocker;
|
||||||
|
Locker fQueryLocker;
|
||||||
NodeListenerTree *fNodeListeners;
|
NodeListenerTree *fNodeListeners;
|
||||||
NodeListenerList fAnyNodeListeners;
|
NodeListenerList fAnyNodeListeners;
|
||||||
EntryListenerTree *fEntryListeners;
|
EntryListenerTree *fEntryListeners;
|
||||||
EntryListenerList fAnyEntryListeners;
|
EntryListenerList fAnyEntryListeners;
|
||||||
|
QueryList fQueries;
|
||||||
BlockAllocator *fBlockAllocator;
|
BlockAllocator *fBlockAllocator;
|
||||||
off_t fBlockSize;
|
off_t fBlockSize;
|
||||||
off_t fAllocatedBlocks;
|
off_t fAllocatedBlocks;
|
||||||
|
|||||||
+74
-12
@@ -43,6 +43,7 @@
|
|||||||
#include "AllocationInfo.h"
|
#include "AllocationInfo.h"
|
||||||
#include "AttributeIndex.h"
|
#include "AttributeIndex.h"
|
||||||
#include "AttributeIterator.h"
|
#include "AttributeIterator.h"
|
||||||
|
#include "AutoDeleter.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "Directory.h"
|
#include "Directory.h"
|
||||||
#include "Entry.h"
|
#include "Entry.h"
|
||||||
@@ -249,6 +250,10 @@ notify_if_stat_changed(Volume *volume, Node *node)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - FS
|
||||||
|
|
||||||
|
|
||||||
// ramfs_mount
|
// ramfs_mount
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
@@ -323,6 +328,10 @@ ramfs_sync(void */*_ns*/)
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - VNodes
|
||||||
|
|
||||||
|
|
||||||
// ramfs_read_vnode
|
// ramfs_read_vnode
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
@@ -375,6 +384,10 @@ FUNCTION(("node: %Ld\n", ((Node*)_node)->GetID()));
|
|||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Nodes
|
||||||
|
|
||||||
|
|
||||||
// ramfs_walk
|
// ramfs_walk
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
@@ -562,6 +575,10 @@ ramfs_write_stat(void *ns, void *_node, struct stat *st, long mask)
|
|||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Files
|
||||||
|
|
||||||
|
|
||||||
// FileCookie
|
// FileCookie
|
||||||
class FileCookie {
|
class FileCookie {
|
||||||
public:
|
public:
|
||||||
@@ -841,6 +858,11 @@ ramfs_access(void *ns, void *_node, int mode)
|
|||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Directories
|
||||||
|
|
||||||
|
|
||||||
// ramfs_rename
|
// ramfs_rename
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
@@ -1330,7 +1352,11 @@ ramfs_free_dir_cookie(void */*ns*/, void */*_node*/, void *_cookie)
|
|||||||
delete cookie;
|
delete cookie;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - FS Stats
|
||||||
|
|
||||||
|
|
||||||
// ramfs_read_fs_stat
|
// ramfs_read_fs_stat
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
@@ -1354,6 +1380,7 @@ ramfs_read_fs_stat(void *ns, struct fs_info *info)
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ramfs_write_fs_stat
|
// ramfs_write_fs_stat
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
@@ -1370,6 +1397,10 @@ ramfs_write_fs_stat(void *ns, struct fs_info *info, long mask)
|
|||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Symlinks
|
||||||
|
|
||||||
|
|
||||||
// ramfs_symlink
|
// ramfs_symlink
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
@@ -1455,6 +1486,10 @@ ramfs_read_link(void *ns, void *_node, char *buffer, size_t *bufferSize)
|
|||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Attributes
|
||||||
|
|
||||||
|
|
||||||
// ramfs_open_attrdir
|
// ramfs_open_attrdir
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
@@ -1703,6 +1738,10 @@ ramfs_stat_attr(void *ns, void *_node, const char *name,
|
|||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Indices
|
||||||
|
|
||||||
|
|
||||||
// IndexDirCookie
|
// IndexDirCookie
|
||||||
class IndexDirCookie {
|
class IndexDirCookie {
|
||||||
public:
|
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.
|
// Query implementation by Axel Dörfler. Slightly adjusted.
|
||||||
//
|
|
||||||
// TODO: Locking!
|
|
||||||
|
|
||||||
// ramfs_open_query
|
// ramfs_open_query
|
||||||
int
|
int
|
||||||
@@ -1922,21 +1961,30 @@ ramfs_open_query(void *ns, const char *queryString, ulong flags, port_id port,
|
|||||||
|
|
||||||
Volume *volume = (Volume *)ns;
|
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);
|
Expression *expression = new Expression((char *)queryString);
|
||||||
if (expression == NULL)
|
if (expression == NULL)
|
||||||
RETURN_ERROR(B_NO_MEMORY);
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
|
ObjectDeleter<Expression> expressionDeleter(expression);
|
||||||
|
|
||||||
if (expression->InitCheck() < B_OK) {
|
if (expression->InitCheck() < B_OK) {
|
||||||
FATAL(("Could not parse query, stopped at: \"%s\"\n", expression->Position()));
|
WARN(("Could not parse query, stopped at: \"%s\"\n",
|
||||||
delete expression;
|
expression->Position()));
|
||||||
RETURN_ERROR(B_BAD_VALUE);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create the query
|
||||||
Query *query = new Query(volume, expression, flags);
|
Query *query = new Query(volume, expression, flags);
|
||||||
if (query == NULL) {
|
if (query == NULL)
|
||||||
delete expression;
|
|
||||||
RETURN_ERROR(B_NO_MEMORY);
|
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)
|
if (flags & B_LIVE_QUERY)
|
||||||
query->SetLiveMode(port, token);
|
query->SetLiveMode(port, token);
|
||||||
@@ -1956,12 +2004,19 @@ ramfs_close_query(void */*ns*/, void */*cookie*/)
|
|||||||
|
|
||||||
// ramfs_free_query_cookie
|
// ramfs_free_query_cookie
|
||||||
int
|
int
|
||||||
ramfs_free_query_cookie(void */*ns*/, void */*node*/, void *cookie)
|
ramfs_free_query_cookie(void *ns, void */*node*/, void *cookie)
|
||||||
{
|
{
|
||||||
FUNCTION_START();
|
FUNCTION_START();
|
||||||
if (cookie == NULL)
|
if (ns == NULL || cookie == NULL)
|
||||||
RETURN_ERROR(B_BAD_VALUE);
|
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;
|
Query *query = (Query *)cookie;
|
||||||
Expression *expression = query->GetExpression();
|
Expression *expression = query->GetExpression();
|
||||||
delete query;
|
delete query;
|
||||||
@@ -1972,14 +2027,21 @@ ramfs_free_query_cookie(void */*ns*/, void */*node*/, void *cookie)
|
|||||||
|
|
||||||
// ramfs_read_query
|
// ramfs_read_query
|
||||||
int
|
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)
|
struct dirent *buffer, size_t bufferSize)
|
||||||
{
|
{
|
||||||
FUNCTION_START();
|
FUNCTION_START();
|
||||||
Query *query = (Query *)cookie;
|
Query *query = (Query *)cookie;
|
||||||
if (query == NULL)
|
if (ns == NULL || query == NULL)
|
||||||
RETURN_ERROR(B_BAD_VALUE);
|
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);
|
status_t status = query->GetNextEntry(buffer, bufferSize);
|
||||||
if (status == B_OK)
|
if (status == B_OK)
|
||||||
*count = 1;
|
*count = 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user