11e7416d9SIngo Weinhold /*
21e7416d9SIngo Weinhold * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
31e7416d9SIngo Weinhold * Distributed under the terms of the MIT License.
41e7416d9SIngo Weinhold */
51e7416d9SIngo Weinhold
61e7416d9SIngo Weinhold
71e7416d9SIngo Weinhold #include "Query.h"
81e7416d9SIngo Weinhold
91e7416d9SIngo Weinhold #include <file_systems/QueryParser.h>
101e7416d9SIngo Weinhold
111e7416d9SIngo Weinhold #include "AttributeCookie.h"
121e7416d9SIngo Weinhold #include "Directory.h"
131e7416d9SIngo Weinhold #include "Index.h"
141e7416d9SIngo Weinhold #include "Node.h"
151e7416d9SIngo Weinhold #include "Volume.h"
161e7416d9SIngo Weinhold
171e7416d9SIngo Weinhold
181e7416d9SIngo Weinhold // #pragma mark - QueryPolicy
191e7416d9SIngo Weinhold
201e7416d9SIngo Weinhold
211e7416d9SIngo Weinhold struct Query::QueryPolicy {
221e7416d9SIngo Weinhold typedef Query Context;
231e7416d9SIngo Weinhold typedef ::Node Entry;
241e7416d9SIngo Weinhold typedef ::Node Node;
253a17bd35SAugustin Cavalier typedef void* NodeHolder;
261e7416d9SIngo Weinhold
271e7416d9SIngo Weinhold struct Index {
281e7416d9SIngo Weinhold Query* query;
291e7416d9SIngo Weinhold ::Index* index;
301e7416d9SIngo Weinhold
IndexQuery::QueryPolicy::Index311e7416d9SIngo Weinhold Index(Context* context)
321e7416d9SIngo Weinhold :
331e7416d9SIngo Weinhold query(context)
341e7416d9SIngo Weinhold {
351e7416d9SIngo Weinhold }
361e7416d9SIngo Weinhold };
371e7416d9SIngo Weinhold
381e7416d9SIngo Weinhold struct IndexIterator : ::IndexIterator {
391e7416d9SIngo Weinhold ::Index* index;
403a17bd35SAugustin Cavalier Entry* entry;
411e7416d9SIngo Weinhold
IndexIteratorQuery::QueryPolicy::IndexIterator421e7416d9SIngo Weinhold IndexIterator(::Index* index)
431e7416d9SIngo Weinhold :
441e7416d9SIngo Weinhold index(index)
451e7416d9SIngo Weinhold {
461e7416d9SIngo Weinhold }
471e7416d9SIngo Weinhold };
481e7416d9SIngo Weinhold
491e7416d9SIngo Weinhold static const int32 kMaxFileNameLength = B_FILE_NAME_LENGTH;
501e7416d9SIngo Weinhold
511e7416d9SIngo Weinhold // Entry interface
521e7416d9SIngo Weinhold
EntryGetParentIDQuery::QueryPolicy531e7416d9SIngo Weinhold static ino_t EntryGetParentID(Entry* entry)
541e7416d9SIngo Weinhold {
550059775cSAugustin Cavalier return entry->GetParentUnchecked()->ID();
561e7416d9SIngo Weinhold }
571e7416d9SIngo Weinhold
EntryGetNodeQuery::QueryPolicy581e7416d9SIngo Weinhold static Node* EntryGetNode(Entry* entry)
591e7416d9SIngo Weinhold {
601e7416d9SIngo Weinhold return entry;
611e7416d9SIngo Weinhold }
621e7416d9SIngo Weinhold
EntryGetNodeIDQuery::QueryPolicy631e7416d9SIngo Weinhold static ino_t EntryGetNodeID(Entry* entry)
641e7416d9SIngo Weinhold {
651e7416d9SIngo Weinhold return entry->ID();
661e7416d9SIngo Weinhold }
671e7416d9SIngo Weinhold
EntryGetNameQuery::QueryPolicy681e7416d9SIngo Weinhold static ssize_t EntryGetName(Entry* entry, void* buffer, size_t bufferSize)
691e7416d9SIngo Weinhold {
701e7416d9SIngo Weinhold const char* name = entry->Name();
711e7416d9SIngo Weinhold size_t nameLength = strlen(name);
721e7416d9SIngo Weinhold if (nameLength >= bufferSize)
731e7416d9SIngo Weinhold return B_BUFFER_OVERFLOW;
741e7416d9SIngo Weinhold
751e7416d9SIngo Weinhold memcpy(buffer, name, nameLength + 1);
761e7416d9SIngo Weinhold return nameLength + 1;
771e7416d9SIngo Weinhold }
781e7416d9SIngo Weinhold
EntryGetNameNoCopyQuery::QueryPolicy793a17bd35SAugustin Cavalier static const char* EntryGetNameNoCopy(NodeHolder& holder, Entry* entry)
801e7416d9SIngo Weinhold {
811e7416d9SIngo Weinhold return entry->Name();
821e7416d9SIngo Weinhold }
831e7416d9SIngo Weinhold
841e7416d9SIngo Weinhold // Index interface
851e7416d9SIngo Weinhold
IndexSetToQuery::QueryPolicy861e7416d9SIngo Weinhold static status_t IndexSetTo(Index& index, const char* attribute)
871e7416d9SIngo Weinhold {
88d07c930cSIngo Weinhold index.index = index.query->fVolume->FindIndex(StringKey(attribute));
891e7416d9SIngo Weinhold return index.index != NULL ? B_OK : B_ENTRY_NOT_FOUND;
901e7416d9SIngo Weinhold }
911e7416d9SIngo Weinhold
IndexUnsetQuery::QueryPolicy921e7416d9SIngo Weinhold static void IndexUnset(Index& index)
931e7416d9SIngo Weinhold {
941e7416d9SIngo Weinhold index.index = NULL;
951e7416d9SIngo Weinhold }
961e7416d9SIngo Weinhold
IndexGetSizeQuery::QueryPolicy97*bb1f2405SAugustin Cavalier static int32 IndexGetSize(Index& index)
981e7416d9SIngo Weinhold {
99*bb1f2405SAugustin Cavalier return index.index->CountEntries();
1001e7416d9SIngo Weinhold }
1011e7416d9SIngo Weinhold
IndexGetTypeQuery::QueryPolicy1021e7416d9SIngo Weinhold static type_code IndexGetType(Index& index)
1031e7416d9SIngo Weinhold {
1041e7416d9SIngo Weinhold return index.index->Type();
1051e7416d9SIngo Weinhold }
1061e7416d9SIngo Weinhold
IndexGetKeySizeQuery::QueryPolicy1071e7416d9SIngo Weinhold static int32 IndexGetKeySize(Index& index)
1081e7416d9SIngo Weinhold {
1091e7416d9SIngo Weinhold return index.index->KeyLength();
1101e7416d9SIngo Weinhold }
1111e7416d9SIngo Weinhold
IndexCreateIteratorQuery::QueryPolicy1121e7416d9SIngo Weinhold static IndexIterator* IndexCreateIterator(Index& index)
1131e7416d9SIngo Weinhold {
1141e7416d9SIngo Weinhold IndexIterator* iterator = new(std::nothrow) IndexIterator(index.index);
1151e7416d9SIngo Weinhold if (iterator == NULL)
1161e7416d9SIngo Weinhold return NULL;
1171e7416d9SIngo Weinhold
1181e7416d9SIngo Weinhold if (!index.index->GetIterator(*iterator)) {
1191e7416d9SIngo Weinhold delete iterator;
1201e7416d9SIngo Weinhold return NULL;
1211e7416d9SIngo Weinhold }
1221e7416d9SIngo Weinhold
1231e7416d9SIngo Weinhold return iterator;
1241e7416d9SIngo Weinhold }
1251e7416d9SIngo Weinhold
1261e7416d9SIngo Weinhold // IndexIterator interface
1271e7416d9SIngo Weinhold
IndexIteratorDeleteQuery::QueryPolicy1281e7416d9SIngo Weinhold static void IndexIteratorDelete(IndexIterator* indexIterator)
1291e7416d9SIngo Weinhold {
1301e7416d9SIngo Weinhold delete indexIterator;
1311e7416d9SIngo Weinhold }
1321e7416d9SIngo Weinhold
IndexIteratorFindQuery::QueryPolicy1331e7416d9SIngo Weinhold static status_t IndexIteratorFind(IndexIterator* indexIterator,
1341e7416d9SIngo Weinhold const void* value, size_t size)
1351e7416d9SIngo Weinhold {
1361e7416d9SIngo Weinhold if (!indexIterator->index->Find(value, size, *indexIterator))
1371e7416d9SIngo Weinhold return B_ENTRY_NOT_FOUND;
1381e7416d9SIngo Weinhold
1391e7416d9SIngo Weinhold return B_OK;
1401e7416d9SIngo Weinhold }
1411e7416d9SIngo Weinhold
IndexIteratorFetchNextEntryQuery::QueryPolicy1423a17bd35SAugustin Cavalier static status_t IndexIteratorFetchNextEntry(IndexIterator* indexIterator,
1433a17bd35SAugustin Cavalier void* value, size_t* _valueLength, size_t bufferSize, size_t* duplicate)
1441e7416d9SIngo Weinhold {
1451e7416d9SIngo Weinhold Node* node = indexIterator->Next(value, _valueLength);
1461e7416d9SIngo Weinhold if (node == NULL)
1471e7416d9SIngo Weinhold return B_ENTRY_NOT_FOUND;
1481e7416d9SIngo Weinhold
1493a17bd35SAugustin Cavalier indexIterator->entry = node;
1501e7416d9SIngo Weinhold return B_OK;
1511e7416d9SIngo Weinhold }
1521e7416d9SIngo Weinhold
IndexIteratorGetEntryQuery::QueryPolicy1533a17bd35SAugustin Cavalier static status_t IndexIteratorGetEntry(Context* context, IndexIterator* indexIterator,
1543a17bd35SAugustin Cavalier NodeHolder& holder, Entry** _entry)
1553a17bd35SAugustin Cavalier {
1563a17bd35SAugustin Cavalier *_entry = indexIterator->entry;
1573a17bd35SAugustin Cavalier return B_OK;
1583a17bd35SAugustin Cavalier }
1593a17bd35SAugustin Cavalier
IndexIteratorSkipDuplicatesQuery::QueryPolicy1603a17bd35SAugustin Cavalier static void IndexIteratorSkipDuplicates(IndexIterator* indexIterator)
1613a17bd35SAugustin Cavalier {
1623a17bd35SAugustin Cavalier // Nothing to do.
1633a17bd35SAugustin Cavalier }
1643a17bd35SAugustin Cavalier
IndexIteratorSuspendQuery::QueryPolicy1651e7416d9SIngo Weinhold static void IndexIteratorSuspend(IndexIterator* indexIterator)
1661e7416d9SIngo Weinhold {
1671e7416d9SIngo Weinhold indexIterator->Suspend();
1681e7416d9SIngo Weinhold }
1691e7416d9SIngo Weinhold
IndexIteratorResumeQuery::QueryPolicy1701e7416d9SIngo Weinhold static void IndexIteratorResume(IndexIterator* indexIterator)
1711e7416d9SIngo Weinhold {
1721e7416d9SIngo Weinhold indexIterator->Resume();
1731e7416d9SIngo Weinhold }
1741e7416d9SIngo Weinhold
1751e7416d9SIngo Weinhold // Node interface
1761e7416d9SIngo Weinhold
NodeGetSizeQuery::QueryPolicy1771e7416d9SIngo Weinhold static const off_t NodeGetSize(Node* node)
1781e7416d9SIngo Weinhold {
1791e7416d9SIngo Weinhold return node->FileSize();
1801e7416d9SIngo Weinhold }
1811e7416d9SIngo Weinhold
NodeGetLastModifiedTimeQuery::QueryPolicy1821e7416d9SIngo Weinhold static time_t NodeGetLastModifiedTime(Node* node)
1831e7416d9SIngo Weinhold {
1841e7416d9SIngo Weinhold return node->ModifiedTime().tv_sec;
1851e7416d9SIngo Weinhold }
1861e7416d9SIngo Weinhold
NodeGetAttributeQuery::QueryPolicy1873a17bd35SAugustin Cavalier static status_t NodeGetAttribute(NodeHolder& nodeHolder, Node* node,
1883a17bd35SAugustin Cavalier const char* attribute, void* buffer, size_t* _size, int32* _type)
1891e7416d9SIngo Weinhold {
1901e7416d9SIngo Weinhold // TODO: Creating a cookie is quite a bit of overhead.
1911e7416d9SIngo Weinhold AttributeCookie* cookie;
192d07c930cSIngo Weinhold status_t error = node->OpenAttribute(StringKey(attribute), O_RDONLY,
193d07c930cSIngo Weinhold cookie);
1941e7416d9SIngo Weinhold if (error != B_OK)
1951e7416d9SIngo Weinhold return error;
1961e7416d9SIngo Weinhold
1971e7416d9SIngo Weinhold error = cookie->ReadAttribute(0, buffer, _size);
1981e7416d9SIngo Weinhold
1991e7416d9SIngo Weinhold // also get the attribute type
2001e7416d9SIngo Weinhold if (error == B_OK) {
2011e7416d9SIngo Weinhold struct stat st;
2021e7416d9SIngo Weinhold error = cookie->ReadAttributeStat(&st);
2031e7416d9SIngo Weinhold if (error == B_OK)
2041e7416d9SIngo Weinhold *_type = st.st_type;
2051e7416d9SIngo Weinhold }
2061e7416d9SIngo Weinhold
2071e7416d9SIngo Weinhold cookie->Close();
2081e7416d9SIngo Weinhold delete cookie;
2091e7416d9SIngo Weinhold
2101e7416d9SIngo Weinhold return error;
2111e7416d9SIngo Weinhold }
2121e7416d9SIngo Weinhold
NodeGetFirstReferrerQuery::QueryPolicy2131e7416d9SIngo Weinhold static Entry* NodeGetFirstReferrer(Node* node)
2141e7416d9SIngo Weinhold {
2151e7416d9SIngo Weinhold return node;
2161e7416d9SIngo Weinhold }
2171e7416d9SIngo Weinhold
NodeGetNextReferrerQuery::QueryPolicy2181e7416d9SIngo Weinhold static Entry* NodeGetNextReferrer(Node* node, Entry* entry)
2191e7416d9SIngo Weinhold {
2201e7416d9SIngo Weinhold return NULL;
2211e7416d9SIngo Weinhold }
2221e7416d9SIngo Weinhold
2231e7416d9SIngo Weinhold // Volume interface
2241e7416d9SIngo Weinhold
ContextGetVolumeIDQuery::QueryPolicy2251e7416d9SIngo Weinhold static dev_t ContextGetVolumeID(Context* context)
2261e7416d9SIngo Weinhold {
2271e7416d9SIngo Weinhold return context->fVolume->ID();
2281e7416d9SIngo Weinhold }
2291e7416d9SIngo Weinhold };
2301e7416d9SIngo Weinhold
2311e7416d9SIngo Weinhold
2321e7416d9SIngo Weinhold // #pragma mark - Query
2331e7416d9SIngo Weinhold
2341e7416d9SIngo Weinhold
Query(Volume * volume)2351e7416d9SIngo Weinhold Query::Query(Volume* volume)
2361e7416d9SIngo Weinhold :
2371e7416d9SIngo Weinhold fVolume(volume),
2381e7416d9SIngo Weinhold fImpl(NULL)
2391e7416d9SIngo Weinhold {
2401e7416d9SIngo Weinhold }
2411e7416d9SIngo Weinhold
2421e7416d9SIngo Weinhold
~Query()2431e7416d9SIngo Weinhold Query::~Query()
2441e7416d9SIngo Weinhold {
2451e7416d9SIngo Weinhold if (fImpl != NULL) {
2461e7416d9SIngo Weinhold if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
2471e7416d9SIngo Weinhold fVolume->RemoveQuery(this);
2481e7416d9SIngo Weinhold
2491e7416d9SIngo Weinhold delete fImpl;
2501e7416d9SIngo Weinhold }
2511e7416d9SIngo Weinhold }
2521e7416d9SIngo Weinhold
2531e7416d9SIngo Weinhold
2541e7416d9SIngo Weinhold /*static*/ status_t
Create(Volume * volume,const char * queryString,uint32 flags,port_id port,uint32 token,Query * & _query)2551e7416d9SIngo Weinhold Query::Create(Volume* volume, const char* queryString, uint32 flags,
2561e7416d9SIngo Weinhold port_id port, uint32 token, Query*& _query)
2571e7416d9SIngo Weinhold {
2581e7416d9SIngo Weinhold Query* query = new(std::nothrow) Query(volume);
2591e7416d9SIngo Weinhold if (query == NULL)
2601e7416d9SIngo Weinhold return B_NO_MEMORY;
2611e7416d9SIngo Weinhold
2621e7416d9SIngo Weinhold status_t error = query->_Init(queryString, flags, port, token);
2631e7416d9SIngo Weinhold if (error != B_OK) {
2641e7416d9SIngo Weinhold delete query;
2651e7416d9SIngo Weinhold return error;
2661e7416d9SIngo Weinhold }
2671e7416d9SIngo Weinhold
2681e7416d9SIngo Weinhold _query = query;
2691e7416d9SIngo Weinhold return B_OK;
2701e7416d9SIngo Weinhold }
2711e7416d9SIngo Weinhold
2721e7416d9SIngo Weinhold
2731e7416d9SIngo Weinhold status_t
Rewind()2741e7416d9SIngo Weinhold Query::Rewind()
2751e7416d9SIngo Weinhold {
2761e7416d9SIngo Weinhold return fImpl->Rewind();
2771e7416d9SIngo Weinhold }
2781e7416d9SIngo Weinhold
2791e7416d9SIngo Weinhold
2801e7416d9SIngo Weinhold status_t
GetNextEntry(struct dirent * entry,size_t size)2811e7416d9SIngo Weinhold Query::GetNextEntry(struct dirent* entry, size_t size)
2821e7416d9SIngo Weinhold {
2831e7416d9SIngo Weinhold return fImpl->GetNextEntry(entry, size);
2841e7416d9SIngo Weinhold }
2851e7416d9SIngo Weinhold
2861e7416d9SIngo Weinhold
2871e7416d9SIngo Weinhold void
LiveUpdate(Node * node,const char * attribute,int32 type,const void * oldKey,size_t oldLength,const void * newKey,size_t newLength)2881e7416d9SIngo Weinhold Query::LiveUpdate(Node* node, const char* attribute, int32 type,
2891e7416d9SIngo Weinhold const void* oldKey, size_t oldLength, const void* newKey, size_t newLength)
2901e7416d9SIngo Weinhold {
2911e7416d9SIngo Weinhold fImpl->LiveUpdate(node, node, attribute, type, (const uint8*)oldKey,
2921e7416d9SIngo Weinhold oldLength, (const uint8*)newKey, newLength);
2931e7416d9SIngo Weinhold }
2941e7416d9SIngo Weinhold
2951e7416d9SIngo Weinhold
2961e7416d9SIngo Weinhold status_t
_Init(const char * queryString,uint32 flags,port_id port,uint32 token)2971e7416d9SIngo Weinhold Query::_Init(const char* queryString, uint32 flags, port_id port, uint32 token)
2981e7416d9SIngo Weinhold {
2991e7416d9SIngo Weinhold status_t error = QueryImpl::Create(this, queryString, flags, port, token,
3001e7416d9SIngo Weinhold fImpl);
3011e7416d9SIngo Weinhold if (error != B_OK)
3021e7416d9SIngo Weinhold return error;
3031e7416d9SIngo Weinhold
3041e7416d9SIngo Weinhold if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
3051e7416d9SIngo Weinhold fVolume->AddQuery(this);
3061e7416d9SIngo Weinhold
3071e7416d9SIngo Weinhold return B_OK;
3081e7416d9SIngo Weinhold }
309