vfs: check userland buffers before reading them.
[haiku.git] / headers / private / file_systems / QueryParser.h
blob4208eb1785bec58ce8bbc3d689aa4edc77a69e55
1 /*
2 * Copyright 2001-2014, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
4 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
5 * This file may be used under the terms of the MIT License.
6 */
7 #ifndef _FILE_SYSTEMS_QUERY_PARSER_H
8 #define _FILE_SYSTEMS_QUERY_PARSER_H
11 /*! Query parsing and evaluation
13 The pattern matching is roughly based on code originally written
14 by J. Kercheval, and on code written by Kenneth Almquist, though
15 it shares no code.
19 // The parser has a very static design, but it will do what is required.
21 // ParseOr(), ParseAnd(), ParseEquation() are guarantying the operator
22 // precedence, that is =,!=,>,<,>=,<= .. && .. ||.
23 // Apparently, the "!" (not) can only be used with brackets.
25 // If you think that there are too few NULL pointer checks in some places
26 // of the code, just read the beginning of the query constructor.
27 // The API is not fully available, just the Query and the Expression class
28 // are.
30 #ifdef FS_SHELL
31 # include <new>
33 # include "fssh_api_wrapper.h"
34 # include "fssh_auto_deleter.h"
35 #else
36 # include <dirent.h>
37 # include <stdlib.h>
38 # include <string.h>
40 # include <algorithm>
41 # include <new>
43 # include <fs_interface.h>
44 # include <fs_query.h>
45 # include <TypeConstants.h>
47 # include <util/SinglyLinkedList.h>
48 # include <util/Stack.h>
50 # include <query_private.h>
52 # include <lock.h>
53 #endif // !FS_SHELL
55 #include <file_systems/QueryParserUtils.h>
58 //#define DEBUG_QUERY
60 #ifndef QUERY_RETURN_ERROR
61 # define QUERY_RETURN_ERROR(error) return (error)
62 #endif
64 #ifndef QUERY_REPORT_ERROR
65 # define QUERY_REPORT_ERROR(error) do {} while (false)
66 #endif
68 #ifndef QUERY_FATAL
69 # define QUERY_FATAL(message...) panic(message)
70 #endif
72 #ifndef QUERY_INFORM
73 # define QUERY_INFORM(message...) dprintf(message)
74 #endif
76 #ifndef QUERY_D
77 # define QUERY_D(block)
78 #endif
81 namespace QueryParser {
84 template<typename QueryPolicy> class Equation;
85 template<typename QueryPolicy> class Expression;
86 template<typename QueryPolicy> class Term;
87 template<typename QueryPolicy> class Query;
90 enum ops {
91 OP_NONE,
93 OP_AND,
94 OP_OR,
96 OP_EQUATION,
97 // is only used for invalid equations
99 OP_EQUAL,
100 OP_UNEQUAL,
101 OP_GREATER_THAN,
102 OP_LESS_THAN,
103 OP_GREATER_THAN_OR_EQUAL,
104 OP_LESS_THAN_OR_EQUAL,
108 template<typename QueryPolicy>
109 union value {
110 int64 Int64;
111 uint64 Uint64;
112 int32 Int32;
113 uint32 Uint32;
114 float Float;
115 double Double;
116 char String[QueryPolicy::kMaxFileNameLength];
120 template<typename QueryPolicy>
121 class Query {
122 public:
123 typedef typename QueryPolicy::Entry Entry;
124 typedef typename QueryPolicy::Index Index;
125 typedef typename QueryPolicy::IndexIterator IndexIterator;
126 typedef typename QueryPolicy::Node Node;
127 typedef typename QueryPolicy::Context Context;
129 public:
130 Query(Context* context,
131 Expression<QueryPolicy>* expression,
132 uint32 flags, port_id port, uint32 token);
133 ~Query();
135 static status_t Create(Context* context, const char* queryString,
136 uint32 flags, port_id port, uint32 token,
137 Query<QueryPolicy>*& _query);
139 status_t Rewind();
140 inline status_t GetNextEntry(struct dirent* dirent, size_t size);
142 void LiveUpdate(Entry* entry, Node* node,
143 const char* attribute, int32 type,
144 const uint8* oldKey, size_t oldLength,
145 const uint8* newKey, size_t newLength);
146 void LiveUpdateRenameMove(Entry* entry, Node* node,
147 ino_t oldDirectoryID, const char* oldName,
148 size_t oldLength, ino_t newDirectoryID,
149 const char* newName, size_t newLength);
151 Expression<QueryPolicy>* GetExpression() const
152 { return fExpression; }
154 uint32 Flags() const
155 { return fFlags; }
157 private:
158 status_t _GetNextEntry(struct dirent* dirent, size_t size);
159 void _SendEntryNotification(Entry* entry,
160 status_t (*notify)(port_id, int32, dev_t, ino_t,
161 const char*, ino_t));
163 private:
164 Context* fContext;
165 Expression<QueryPolicy>* fExpression;
166 Equation<QueryPolicy>* fCurrent;
167 IndexIterator* fIterator;
168 Index fIndex;
169 Stack<Equation<QueryPolicy>*> fStack;
171 uint32 fFlags;
172 port_id fPort;
173 int32 fToken;
174 bool fNeedsEntry;
178 /*! Abstract base class for the operator/equation classes.
180 template<typename QueryPolicy>
181 class Term {
182 public:
183 typedef typename QueryPolicy::Entry Entry;
184 typedef typename QueryPolicy::Index Index;
185 typedef typename QueryPolicy::IndexIterator IndexIterator;
186 typedef typename QueryPolicy::Node Node;
187 typedef typename QueryPolicy::Context Context;
189 public:
190 Term(int8 op) : fOp(op), fParent(NULL) {}
191 virtual ~Term() {}
193 int8 Op() const { return fOp; }
195 void SetParent(Term<QueryPolicy>* parent)
196 { fParent = parent; }
197 Term<QueryPolicy>* Parent() const { return fParent; }
199 virtual status_t Match(Entry* entry, Node* node,
200 const char* attribute = NULL, int32 type = 0,
201 const uint8* key = NULL, size_t size = 0) = 0;
202 virtual void Complement() = 0;
204 virtual void CalculateScore(Index& index) = 0;
205 virtual int32 Score() const = 0;
207 virtual status_t InitCheck() = 0;
209 virtual bool NeedsEntry() = 0;
211 #ifdef DEBUG_QUERY
212 virtual void PrintToStream() = 0;
213 #endif
215 protected:
216 int8 fOp;
217 Term<QueryPolicy>* fParent;
221 /*! An Equation object represents an "attribute-equation operator-value" pair.
223 Although an Equation object is quite independent from the volume on which
224 the query is run, there are some dependencies that are produced while
225 querying:
226 The type/size of the value, the score, and if it has an index or not.
227 So you could run more than one query on the same volume, but it might return
228 wrong values when it runs concurrently on another volume.
229 That's not an issue right now, because we run single-threaded and don't use
230 queries more than once.
232 template<typename QueryPolicy>
233 class Equation : public Term<QueryPolicy> {
234 public:
235 typedef typename QueryPolicy::Entry Entry;
236 typedef typename QueryPolicy::Index Index;
237 typedef typename QueryPolicy::IndexIterator IndexIterator;
238 typedef typename QueryPolicy::Node Node;
239 typedef typename QueryPolicy::Context Context;
241 public:
242 Equation(char** expression);
243 virtual ~Equation();
245 virtual status_t InitCheck();
247 status_t ParseQuotedString(char** _start, char** _end);
248 char* CopyString(char* start, char* end);
250 virtual status_t Match(Entry* entry, Node* node,
251 const char* attribute = NULL, int32 type = 0,
252 const uint8* key = NULL, size_t size = 0);
253 virtual void Complement();
255 status_t PrepareQuery(Context* context, Index& index,
256 IndexIterator** iterator, bool queryNonIndexed);
257 status_t GetNextMatching(Context* context,
258 IndexIterator* iterator, struct dirent* dirent,
259 size_t bufferSize);
261 virtual void CalculateScore(Index &index);
262 virtual int32 Score() const { return fScore; }
264 virtual bool NeedsEntry();
266 #ifdef DEBUG_QUERY
267 virtual void PrintToStream();
268 #endif
270 private:
271 Equation(const Equation& other);
272 Equation& operator=(const Equation& other);
273 // no implementation
275 status_t ConvertValue(type_code type);
276 bool CompareTo(const uint8* value, size_t size);
277 uint8* Value() const { return (uint8*)&fValue; }
278 status_t MatchEmptyString();
280 char* fAttribute;
281 char* fString;
282 union value<QueryPolicy> fValue;
283 type_code fType;
284 size_t fSize;
285 bool fIsPattern;
287 int32 fScore;
288 bool fHasIndex;
292 /*! The Operator class does not represent a generic operator, but only those
293 that combine two equations, namely "or", and "and".
295 template<typename QueryPolicy>
296 class Operator : public Term<QueryPolicy> {
297 public:
298 typedef typename QueryPolicy::Entry Entry;
299 typedef typename QueryPolicy::Index Index;
300 typedef typename QueryPolicy::IndexIterator IndexIterator;
301 typedef typename QueryPolicy::Node Node;
302 typedef typename QueryPolicy::Context Context;
304 public:
305 Operator(Term<QueryPolicy>* left, int8 op,
306 Term<QueryPolicy>* right);
307 virtual ~Operator();
309 Term<QueryPolicy>* Left() const { return fLeft; }
310 Term<QueryPolicy>* Right() const { return fRight; }
312 virtual status_t Match(Entry* entry, Node* node,
313 const char* attribute = NULL, int32 type = 0,
314 const uint8* key = NULL, size_t size = 0);
315 virtual void Complement();
317 virtual void CalculateScore(Index& index);
318 virtual int32 Score() const;
320 virtual status_t InitCheck();
322 virtual bool NeedsEntry();
324 #ifdef DEBUG_QUERY
325 virtual void PrintToStream();
326 #endif
328 private:
329 Operator(const Operator& other);
330 Operator& operator=(const Operator& other);
331 // no implementation
333 Term<QueryPolicy>* fLeft;
334 Term<QueryPolicy>* fRight;
338 template<typename QueryPolicy>
339 class Expression {
340 public:
341 typedef typename QueryPolicy::Entry Entry;
342 typedef typename QueryPolicy::Index Index;
343 typedef typename QueryPolicy::IndexIterator IndexIterator;
344 typedef typename QueryPolicy::Node Node;
345 typedef typename QueryPolicy::Context Context;
347 public:
348 Expression(char* expr);
349 ~Expression();
351 status_t InitCheck();
352 const char* Position() const { return fPosition; }
353 Term<QueryPolicy>* Root() const { return fTerm; }
355 protected:
356 Term<QueryPolicy>* ParseOr(char** expr);
357 Term<QueryPolicy>* ParseAnd(char** expr);
358 Term<QueryPolicy>* ParseEquation(char** expr);
360 bool IsOperator(char** expr, char op);
362 private:
363 Expression(const Expression& other);
364 Expression& operator=(const Expression& other);
365 // no implementation
367 char* fPosition;
368 Term<QueryPolicy>* fTerm;
372 // #pragma mark -
375 template<typename QueryPolicy>
376 Equation<QueryPolicy>::Equation(char** expr)
378 Term<QueryPolicy>(OP_EQUATION),
379 fAttribute(NULL),
380 fString(NULL),
381 fType(0),
382 fIsPattern(false)
384 char* string = *expr;
385 char* start = string;
386 char* end = NULL;
388 // Since the equation is the integral part of any query, we're just parsing
389 // the whole thing here.
390 // The whitespace at the start is already removed in
391 // Expression::ParseEquation()
393 if (*start == '"' || *start == '\'') {
394 // string is quoted (start has to be on the beginning of a string)
395 if (ParseQuotedString(&start, &end) < B_OK)
396 return;
398 // set string to a valid start of the equation symbol
399 string = end + 2;
400 skipWhitespace(&string);
401 if (*string != '=' && *string != '<' && *string != '>'
402 && *string != '!') {
403 *expr = string;
404 return;
406 } else {
407 // search the (in)equation for the actual equation symbol (and for other operators
408 // in case the equation is malformed)
409 while (*string && *string != '=' && *string != '<' && *string != '>'
410 && *string != '!' && *string != '&' && *string != '|') {
411 string++;
414 // get the attribute string (and trim whitespace), in case
415 // the string was not quoted
416 end = string - 1;
417 skipWhitespaceReverse(&end, start);
420 // attribute string is empty (which is not allowed)
421 if (start > end)
422 return;
424 // At this point, "start" points to the beginning of the string, "end"
425 // points to the last character of the string, and "string" points to the
426 // first character of the equation symbol
428 // test for the right symbol (as this doesn't need any memory)
429 switch (*string) {
430 case '=':
431 Term<QueryPolicy>::fOp = OP_EQUAL;
432 break;
433 case '>':
434 Term<QueryPolicy>::fOp = *(string + 1) == '='
435 ? OP_GREATER_THAN_OR_EQUAL : OP_GREATER_THAN;
436 break;
437 case '<':
438 Term<QueryPolicy>::fOp = *(string + 1) == '='
439 ? OP_LESS_THAN_OR_EQUAL : OP_LESS_THAN;
440 break;
441 case '!':
442 if (*(string + 1) != '=')
443 return;
444 Term<QueryPolicy>::fOp = OP_UNEQUAL;
445 break;
447 // any invalid characters will be rejected
448 default:
449 *expr = string;
450 return;
453 // lets change "start" to point to the first character after the symbol
454 if (*(string + 1) == '=')
455 string++;
456 string++;
457 skipWhitespace(&string);
459 // allocate & copy the attribute string
461 fAttribute = CopyString(start, end);
462 if (fAttribute == NULL)
463 return;
465 start = string;
466 if (*start == '"' || *start == '\'') {
467 // string is quoted (start has to be on the beginning of a string)
468 if (ParseQuotedString(&start, &end) < B_OK)
469 return;
471 string = end + 2;
472 skipWhitespace(&string);
473 } else {
474 while (*string && *string != '&' && *string != '|' && *string != ')')
475 string++;
477 end = string - 1;
478 skipWhitespaceReverse(&end, start);
481 // at this point, "start" will point to the first character of the value,
482 // "end" will point to its last character, and "start" to the first non-
483 // whitespace character after the value string
485 fString = CopyString(start, end);
486 if (fString == NULL)
487 return;
489 // patterns are only allowed for these operations (and strings)
490 if (Term<QueryPolicy>::fOp == OP_EQUAL
491 || Term<QueryPolicy>::fOp == OP_UNEQUAL) {
492 fIsPattern = isPattern(fString);
493 if (fIsPattern && isValidPattern(fString) < B_OK) {
494 // we only want to have valid patterns; setting fString
495 // to NULL will cause InitCheck() to fail
496 free(fString);
497 fString = NULL;
501 *expr = string;
505 template<typename QueryPolicy>
506 Equation<QueryPolicy>::~Equation()
508 free(fAttribute);
509 free(fString);
513 template<typename QueryPolicy>
514 status_t
515 Equation<QueryPolicy>::InitCheck()
517 if (fAttribute == NULL || fString == NULL
518 || Term<QueryPolicy>::fOp == OP_NONE) {
519 return B_BAD_VALUE;
522 return B_OK;
526 template<typename QueryPolicy>
527 status_t
528 Equation<QueryPolicy>::ParseQuotedString(char** _start, char** _end)
530 char* start = *_start;
531 char quote = *start++;
532 char* end = start;
534 for (; *end && *end != quote; end++) {
535 if (*end == '\\')
536 end++;
538 if (*end == '\0')
539 return B_BAD_VALUE;
541 *_start = start;
542 *_end = end - 1;
544 return B_OK;
548 template<typename QueryPolicy>
549 char*
550 Equation<QueryPolicy>::CopyString(char* start, char* end)
552 // end points to the last character of the string - and the length
553 // also has to include the null-termination
554 int32 length = end + 2 - start;
555 // just to make sure; since that's the max. attribute name length and
556 // the max. string in an index, it make sense to have it that way
557 if (length > QueryPolicy::kMaxFileNameLength || length <= 0)
558 return NULL;
560 char* copy = (char*)malloc(length);
561 if (copy == NULL)
562 return NULL;
564 memcpy(copy, start, length - 1);
565 copy[length - 1] = '\0';
567 return copy;
571 template<typename QueryPolicy>
572 status_t
573 Equation<QueryPolicy>::ConvertValue(type_code type)
575 // Has the type already been converted?
576 if (type == fType)
577 return B_OK;
579 char* string = fString;
581 switch (type) {
582 case B_MIME_STRING_TYPE:
583 type = B_STRING_TYPE;
584 // supposed to fall through
585 case B_STRING_TYPE:
586 strncpy(fValue.String, string, QueryPolicy::kMaxFileNameLength);
587 fValue.String[QueryPolicy::kMaxFileNameLength - 1] = '\0';
588 fSize = strlen(fValue.String);
589 break;
590 case B_INT32_TYPE:
591 fValue.Int32 = strtol(string, &string, 0);
592 fSize = sizeof(int32);
593 break;
594 case B_UINT32_TYPE:
595 fValue.Int32 = strtoul(string, &string, 0);
596 fSize = sizeof(uint32);
597 break;
598 case B_INT64_TYPE:
599 fValue.Int64 = strtoll(string, &string, 0);
600 fSize = sizeof(int64);
601 break;
602 case B_UINT64_TYPE:
603 fValue.Uint64 = strtoull(string, &string, 0);
604 fSize = sizeof(uint64);
605 break;
606 case B_FLOAT_TYPE:
607 fValue.Float = strtod(string, &string);
608 fSize = sizeof(float);
609 break;
610 case B_DOUBLE_TYPE:
611 fValue.Double = strtod(string, &string);
612 fSize = sizeof(double);
613 break;
614 default:
615 QUERY_FATAL("query value conversion to 0x%x requested!\n",
616 (int)type);
617 // should we fail here or just do a safety int32 conversion?
618 return B_ERROR;
621 fType = type;
623 // patterns are only allowed for string types
624 if (fType != B_STRING_TYPE && fIsPattern)
625 fIsPattern = false;
627 return B_OK;
631 /*! Returns true when the key matches the equation. You have to
632 call ConvertValue() before this one.
634 template<typename QueryPolicy>
635 bool
636 Equation<QueryPolicy>::CompareTo(const uint8* value, size_t size)
638 int32 compare;
640 // fIsPattern is only true if it's a string type, and fOp OP_EQUAL, or
641 // OP_UNEQUAL
642 if (fIsPattern) {
643 // we have already validated the pattern, so we don't check for failing
644 // here - if something is broken, and matchString() returns an error,
645 // we just don't match
646 compare = matchString(fValue.String, (char*)value) == MATCH_OK ? 0 : 1;
647 } else
648 compare = compareKeys(fType, value, size, Value(), fSize);
650 switch (Term<QueryPolicy>::fOp) {
651 case OP_EQUAL:
652 return compare == 0;
653 case OP_UNEQUAL:
654 return compare != 0;
655 case OP_LESS_THAN:
656 return compare < 0;
657 case OP_LESS_THAN_OR_EQUAL:
658 return compare <= 0;
659 case OP_GREATER_THAN:
660 return compare > 0;
661 case OP_GREATER_THAN_OR_EQUAL:
662 return compare >= 0;
664 QUERY_FATAL("Unknown/Unsupported operation: %d\n", Term<QueryPolicy>::fOp);
665 return false;
669 template<typename QueryPolicy>
670 void
671 Equation<QueryPolicy>::Complement()
673 QUERY_D(if (fOp <= OP_EQUATION || fOp > OP_LESS_THAN_OR_EQUAL) {
674 QUERY_FATAL("op out of range!\n");
675 return;
678 int8 complementOp[] = {OP_UNEQUAL, OP_EQUAL, OP_LESS_THAN_OR_EQUAL,
679 OP_GREATER_THAN_OR_EQUAL, OP_LESS_THAN, OP_GREATER_THAN};
680 Term<QueryPolicy>::fOp = complementOp[Term<QueryPolicy>::fOp - OP_EQUAL];
684 template<typename QueryPolicy>
685 status_t
686 Equation<QueryPolicy>::MatchEmptyString()
688 // There is no matching attribute, we will just bail out if we
689 // already know that our value is not of a string type.
690 // If not, it will be converted to a string - and then be compared with "".
691 // That's why we have to call ConvertValue() here - but it will be
692 // a cheap call for the next time
693 // TODO: Should we do this only for OP_UNEQUAL?
694 if (fType != 0 && fType != B_STRING_TYPE)
695 return NO_MATCH;
697 status_t status = ConvertValue(B_STRING_TYPE);
698 if (status == B_OK)
699 status = CompareTo((const uint8*)"", fSize) ? MATCH_OK : NO_MATCH;
701 return status;
705 /*! Matches the node's attribute value with the equation.
706 Returns MATCH_OK if it matches, NO_MATCH if not, < 0 if something went
707 wrong.
709 template<typename QueryPolicy>
710 status_t
711 Equation<QueryPolicy>::Match(Entry* entry, Node* node,
712 const char* attributeName, int32 type, const uint8* key, size_t size)
714 // get a pointer to the attribute in question
715 union value<QueryPolicy> value;
716 uint8* buffer = (uint8*)&value;
717 const size_t bufferSize = sizeof(value);
719 // first, check if we are matching for a live query and use that value
720 if (attributeName != NULL && !strcmp(fAttribute, attributeName)) {
721 if (key == NULL) {
722 if (type == B_STRING_TYPE)
723 return MatchEmptyString();
725 return NO_MATCH;
727 buffer = const_cast<uint8*>(key);
728 } else if (!strcmp(fAttribute, "name")) {
729 // if not, check for "fake" attributes ("name", "size", "last_modified")
730 if (entry == NULL)
731 return B_ERROR;
732 buffer = (uint8*)QueryPolicy::EntryGetNameNoCopy(entry, buffer,
733 sizeof(value));
734 if (buffer == NULL)
735 return B_ERROR;
737 type = B_STRING_TYPE;
738 size = strlen((const char*)buffer);
739 } else if (!strcmp(fAttribute, "size")) {
740 value.Int64 = QueryPolicy::NodeGetSize(node);
741 type = B_INT64_TYPE;
742 } else if (!strcmp(fAttribute, "last_modified")) {
743 value.Int32 = QueryPolicy::NodeGetLastModifiedTime(node);
744 type = B_INT32_TYPE;
745 } else {
746 // then for attributes
747 size = bufferSize;
748 if (QueryPolicy::NodeGetAttribute(node, fAttribute, buffer, &size,
749 &type) != B_OK) {
750 return MatchEmptyString();
754 // prepare own value for use, if it is possible to convert it
755 status_t status = ConvertValue(type);
756 if (status == B_OK)
757 status = CompareTo(buffer, size) ? MATCH_OK : NO_MATCH;
759 QUERY_RETURN_ERROR(status);
763 template<typename QueryPolicy>
764 void
765 Equation<QueryPolicy>::CalculateScore(Index &index)
767 // As always, these values could be tuned and refined.
768 // And the code could also need some real world testing :-)
770 // do we have to operate on a "foreign" index?
771 if (Term<QueryPolicy>::fOp == OP_UNEQUAL
772 || QueryPolicy::IndexSetTo(index, fAttribute) < B_OK) {
773 fScore = 0;
774 return;
777 // if we have a pattern, how much does it help our search?
778 if (fIsPattern)
779 fScore = getFirstPatternSymbol(fString) << 3;
780 else {
781 // Score by operator
782 if (Term<QueryPolicy>::fOp == OP_EQUAL) {
783 // higher than pattern="255 chars+*"
784 fScore = 2048;
785 } else {
786 // the pattern search is regarded cheaper when you have at
787 // least one character to set your index to
788 fScore = 5;
792 // take index size into account
793 fScore = QueryPolicy::IndexGetWeightedScore(index, fScore);
797 template<typename QueryPolicy>
798 status_t
799 Equation<QueryPolicy>::PrepareQuery(Context* /*context*/, Index& index,
800 IndexIterator** iterator, bool queryNonIndexed)
802 status_t status = QueryPolicy::IndexSetTo(index, fAttribute);
804 // if we should query attributes without an index, we can just proceed here
805 if (status != B_OK && !queryNonIndexed)
806 return B_ENTRY_NOT_FOUND;
808 type_code type;
810 // Special case for OP_UNEQUAL - it will always operate through the whole
811 // index but we need the call to the original index to get the correct type
812 if (status != B_OK || Term<QueryPolicy>::fOp == OP_UNEQUAL) {
813 // Try to get an index that holds all files (name)
814 // Also sets the default type for all attributes without index
815 // to string.
816 type = status < B_OK ? B_STRING_TYPE : QueryPolicy::IndexGetType(index);
818 if (QueryPolicy::IndexSetTo(index, "name") != B_OK)
819 return B_ENTRY_NOT_FOUND;
821 fHasIndex = false;
822 } else {
823 fHasIndex = true;
824 type = QueryPolicy::IndexGetType(index);
827 if (ConvertValue(type) < B_OK)
828 return B_BAD_VALUE;
830 *iterator = QueryPolicy::IndexCreateIterator(index);
831 if (*iterator == NULL)
832 return B_NO_MEMORY;
834 if ((Term<QueryPolicy>::fOp == OP_EQUAL
835 || Term<QueryPolicy>::fOp == OP_GREATER_THAN
836 || Term<QueryPolicy>::fOp == OP_GREATER_THAN_OR_EQUAL || fIsPattern)
837 && fHasIndex) {
838 // set iterator to the exact position
840 int32 keySize = QueryPolicy::IndexGetKeySize(index);
842 // At this point, fIsPattern is only true if it's a string type, and fOp
843 // is either OP_EQUAL or OP_UNEQUAL
844 if (fIsPattern) {
845 // let's see if we can use the beginning of the key for positioning
846 // the iterator and adjust the key size; if not, just leave the
847 // iterator at the start and return success
848 keySize = getFirstPatternSymbol(fString);
849 if (keySize <= 0)
850 return B_OK;
853 if (keySize == 0) {
854 // B_STRING_TYPE doesn't have a fixed length, so it was set
855 // to 0 before - we compute the correct value here
856 if (fType == B_STRING_TYPE) {
857 keySize = strlen(fValue.String);
859 // The empty string is a special case - we normally don't check
860 // for the trailing null byte, in the case for the empty string
861 // we do it explicitly, because there can't be keys in the
862 // B+tree with a length of zero
863 if (keySize == 0)
864 keySize = 1;
865 } else
866 QUERY_RETURN_ERROR(B_ENTRY_NOT_FOUND);
869 status = QueryPolicy::IndexIteratorFind(*iterator, Value(), keySize);
870 if (Term<QueryPolicy>::fOp == OP_EQUAL && !fIsPattern)
871 return status;
872 else if (status == B_ENTRY_NOT_FOUND
873 && (fIsPattern || Term<QueryPolicy>::fOp == OP_GREATER_THAN
874 || Term<QueryPolicy>::fOp == OP_GREATER_THAN_OR_EQUAL))
875 return B_OK;
877 QUERY_RETURN_ERROR(status);
880 return B_OK;
884 template<typename QueryPolicy>
885 status_t
886 Equation<QueryPolicy>::GetNextMatching(Context* context,
887 IndexIterator* iterator, struct dirent* dirent, size_t bufferSize)
889 while (true) {
890 union value<QueryPolicy> indexValue;
891 size_t keyLength;
892 Entry* entry = NULL;
894 status_t status = QueryPolicy::IndexIteratorGetNextEntry(iterator,
895 &indexValue, &keyLength, (size_t)sizeof(indexValue), &entry);
896 if (status != B_OK)
897 return status;
899 // only compare against the index entry when this is the correct
900 // index for the equation
901 if (fHasIndex && !CompareTo((uint8*)&indexValue, keyLength)) {
902 // They aren't equal? Let the operation decide what to do. Since
903 // we always start at the beginning of the index (or the correct
904 // position), only some needs to be stopped if the entry doesn't
905 // fit.
906 if (Term<QueryPolicy>::fOp == OP_LESS_THAN
907 || Term<QueryPolicy>::fOp == OP_LESS_THAN_OR_EQUAL
908 || (Term<QueryPolicy>::fOp == OP_EQUAL && !fIsPattern))
909 return B_ENTRY_NOT_FOUND;
911 continue;
914 // TODO: check user permissions here - but which one?!
915 // we could filter out all those where we don't have
916 // read access... (we should check for every parent
917 // directory if the X_OK is allowed)
918 // Although it's quite expensive to open all parents,
919 // it's likely that the application that runs the
920 // query will do something similar (and we don't have
921 // to do it for root, either).
923 // go up in the tree until a &&-operator is found, and check if the
924 // node matches with the rest of the expression - we don't have to
925 // check ||-operators for that
926 Term<QueryPolicy>* term = this;
927 status = MATCH_OK;
929 if (!fHasIndex)
930 status = Match(entry, QueryPolicy::EntryGetNode(entry));
932 while (term != NULL && status == MATCH_OK) {
933 Operator<QueryPolicy>* parent
934 = (Operator<QueryPolicy>*)term->Parent();
935 if (parent == NULL)
936 break;
938 if (parent->Op() == OP_AND) {
939 // choose the other child of the parent
940 Term<QueryPolicy>* other = parent->Right();
941 if (other == term)
942 other = parent->Left();
944 if (other == NULL) {
945 QUERY_FATAL("&&-operator has only one child... "
946 "(parent = %p)\n", parent);
947 break;
949 status = other->Match(entry, QueryPolicy::EntryGetNode(entry));
950 if (status < 0) {
951 QUERY_REPORT_ERROR(status);
952 status = NO_MATCH;
955 term = (Term<QueryPolicy>*)parent;
958 if (status == MATCH_OK) {
959 ssize_t nameLength = QueryPolicy::EntryGetName(entry,
960 dirent->d_name,
961 (const char*)dirent + bufferSize - dirent->d_name);
962 if (nameLength < 0)
963 QUERY_RETURN_ERROR(nameLength);
965 dirent->d_dev = QueryPolicy::ContextGetVolumeID(context);
966 dirent->d_ino = QueryPolicy::EntryGetNodeID(entry);
967 dirent->d_pdev = dirent->d_dev;
968 dirent->d_pino = QueryPolicy::EntryGetParentID(entry);
969 dirent->d_reclen = sizeof(struct dirent) + strlen(dirent->d_name);
972 if (status == MATCH_OK)
973 return B_OK;
975 QUERY_RETURN_ERROR(B_ERROR);
979 template<typename QueryPolicy>
980 bool
981 Equation<QueryPolicy>::NeedsEntry()
983 return strcmp(fAttribute, "name") == 0;
987 // #pragma mark -
990 template<typename QueryPolicy>
991 Operator<QueryPolicy>::Operator(Term<QueryPolicy>* left, int8 op,
992 Term<QueryPolicy>* right)
994 Term<QueryPolicy>(op),
995 fLeft(left),
996 fRight(right)
998 if (left)
999 left->SetParent(this);
1000 if (right)
1001 right->SetParent(this);
1005 template<typename QueryPolicy>
1006 Operator<QueryPolicy>::~Operator()
1008 delete fLeft;
1009 delete fRight;
1013 template<typename QueryPolicy>
1014 status_t
1015 Operator<QueryPolicy>::Match(Entry* entry, Node* node, const char* attribute,
1016 int32 type, const uint8* key, size_t size)
1018 if (Term<QueryPolicy>::fOp == OP_AND) {
1019 status_t status = fLeft->Match(entry, node, attribute, type, key,
1020 size);
1021 if (status != MATCH_OK)
1022 return status;
1024 return fRight->Match(entry, node, attribute, type, key, size);
1025 } else {
1026 // choose the term with the better score for OP_OR
1027 Term<QueryPolicy>* first;
1028 Term<QueryPolicy>* second;
1029 if (fRight->Score() > fLeft->Score()) {
1030 first = fLeft;
1031 second = fRight;
1032 } else {
1033 first = fRight;
1034 second = fLeft;
1037 status_t status = first->Match(entry, node, attribute, type, key,
1038 size);
1039 if (status != NO_MATCH)
1040 return status;
1042 return second->Match(entry, node, attribute, type, key, size);
1047 template<typename QueryPolicy>
1048 void
1049 Operator<QueryPolicy>::Complement()
1051 if (Term<QueryPolicy>::fOp == OP_AND)
1052 Term<QueryPolicy>::fOp = OP_OR;
1053 else
1054 Term<QueryPolicy>::fOp = OP_AND;
1056 fLeft->Complement();
1057 fRight->Complement();
1061 template<typename QueryPolicy>
1062 void
1063 Operator<QueryPolicy>::CalculateScore(Index &index)
1065 fLeft->CalculateScore(index);
1066 fRight->CalculateScore(index);
1070 template<typename QueryPolicy>
1071 int32
1072 Operator<QueryPolicy>::Score() const
1074 if (Term<QueryPolicy>::fOp == OP_AND) {
1075 // return the one with the better score
1076 if (fRight->Score() > fLeft->Score())
1077 return fRight->Score();
1079 return fLeft->Score();
1082 // for OP_OR, be honest, and return the one with the worse score
1083 if (fRight->Score() < fLeft->Score())
1084 return fRight->Score();
1086 return fLeft->Score();
1090 template<typename QueryPolicy>
1091 status_t
1092 Operator<QueryPolicy>::InitCheck()
1094 if ((Term<QueryPolicy>::fOp != OP_AND && Term<QueryPolicy>::fOp != OP_OR)
1095 || fLeft == NULL || fLeft->InitCheck() < B_OK
1096 || fRight == NULL || fRight->InitCheck() < B_OK)
1097 return B_ERROR;
1099 return B_OK;
1103 template<typename QueryPolicy>
1104 bool
1105 Operator<QueryPolicy>::NeedsEntry()
1107 return ((fLeft && fLeft->NeedsEntry()) || (fRight && fRight->NeedsEntry()));
1111 // #pragma mark -
1113 #ifdef DEBUG_QUERY
1115 template<typename QueryPolicy>
1116 void
1117 Operator<QueryPolicy>::PrintToStream()
1119 QUERY_D(__out("( "));
1120 if (fLeft != NULL)
1121 fLeft->PrintToStream();
1123 const char* op;
1124 switch (Term<QueryPolicy>::fOp) {
1125 case OP_OR: op = "OR"; break;
1126 case OP_AND: op = "AND"; break;
1127 default: op = "?"; break;
1129 QUERY_D(__out(" %s ", op));
1131 if (fRight != NULL)
1132 fRight->PrintToStream();
1134 QUERY_D(__out(" )"));
1138 template<typename QueryPolicy>
1139 void
1140 Equation<QueryPolicy>::PrintToStream()
1142 const char* symbol = "???";
1143 switch (Term<QueryPolicy>::fOp) {
1144 case OP_EQUAL: symbol = "=="; break;
1145 case OP_UNEQUAL: symbol = "!="; break;
1146 case OP_GREATER_THAN: symbol = ">"; break;
1147 case OP_GREATER_THAN_OR_EQUAL: symbol = ">="; break;
1148 case OP_LESS_THAN: symbol = "<"; break;
1149 case OP_LESS_THAN_OR_EQUAL: symbol = "<="; break;
1151 QUERY_D(__out("[\"%s\" %s \"%s\"]", fAttribute, symbol, fString));
1154 #endif // DEBUG_QUERY
1156 // #pragma mark -
1159 template<typename QueryPolicy>
1160 Expression<QueryPolicy>::Expression(char* expr)
1162 if (expr == NULL)
1163 return;
1165 fTerm = ParseOr(&expr);
1166 if (fTerm != NULL && fTerm->InitCheck() < B_OK) {
1167 QUERY_FATAL("Corrupt tree in expression!\n");
1168 delete fTerm;
1169 fTerm = NULL;
1171 QUERY_D(if (fTerm != NULL) {
1172 fTerm->PrintToStream();
1173 QUERY_D(__out("\n"));
1174 if (*expr != '\0')
1175 PRINT(("Unexpected end of string: \"%s\"!\n", expr));
1177 fPosition = expr;
1181 template<typename QueryPolicy>
1182 Expression<QueryPolicy>::~Expression()
1184 delete fTerm;
1188 template<typename QueryPolicy>
1189 Term<QueryPolicy>*
1190 Expression<QueryPolicy>::ParseEquation(char** expr)
1192 skipWhitespace(expr);
1194 bool _not = false;
1195 if (**expr == '!') {
1196 skipWhitespace(expr, 1);
1197 if (**expr != '(')
1198 return NULL;
1200 _not = true;
1203 if (**expr == ')') {
1204 // shouldn't be handled here
1205 return NULL;
1206 } else if (**expr == '(') {
1207 skipWhitespace(expr, 1);
1209 Term<QueryPolicy>* term = ParseOr(expr);
1211 skipWhitespace(expr);
1213 if (**expr != ')') {
1214 delete term;
1215 return NULL;
1218 // If the term is negated, we just complement the tree, to get
1219 // rid of the not, a.k.a. DeMorgan's Law.
1220 if (_not)
1221 term->Complement();
1223 skipWhitespace(expr, 1);
1225 return term;
1228 Equation<QueryPolicy>* equation
1229 = new(std::nothrow) Equation<QueryPolicy>(expr);
1230 if (equation == NULL || equation->InitCheck() < B_OK) {
1231 delete equation;
1232 return NULL;
1234 return equation;
1238 template<typename QueryPolicy>
1239 Term<QueryPolicy>*
1240 Expression<QueryPolicy>::ParseAnd(char** expr)
1242 Term<QueryPolicy>* left = ParseEquation(expr);
1243 if (left == NULL)
1244 return NULL;
1246 while (IsOperator(expr, '&')) {
1247 Term<QueryPolicy>* right = ParseAnd(expr);
1248 Term<QueryPolicy>* newParent = NULL;
1250 if (right == NULL
1251 || (newParent = new(std::nothrow) Operator<QueryPolicy>(left,
1252 OP_AND, right)) == NULL) {
1253 delete left;
1254 delete right;
1256 return NULL;
1258 left = newParent;
1261 return left;
1265 template<typename QueryPolicy>
1266 Term<QueryPolicy>*
1267 Expression<QueryPolicy>::ParseOr(char** expr)
1269 Term<QueryPolicy>* left = ParseAnd(expr);
1270 if (left == NULL)
1271 return NULL;
1273 while (IsOperator(expr, '|')) {
1274 Term<QueryPolicy>* right = ParseAnd(expr);
1275 Term<QueryPolicy>* newParent = NULL;
1277 if (right == NULL
1278 || (newParent = new(std::nothrow) Operator<QueryPolicy>(left, OP_OR,
1279 right)) == NULL) {
1280 delete left;
1281 delete right;
1283 return NULL;
1285 left = newParent;
1288 return left;
1292 template<typename QueryPolicy>
1293 bool
1294 Expression<QueryPolicy>::IsOperator(char** expr, char op)
1296 char* string = *expr;
1298 if (*string == op && *(string + 1) == op) {
1299 *expr += 2;
1300 return true;
1302 return false;
1306 template<typename QueryPolicy>
1307 status_t
1308 Expression<QueryPolicy>::InitCheck()
1310 if (fTerm == NULL)
1311 return B_BAD_VALUE;
1313 return B_OK;
1317 // #pragma mark -
1320 template<typename QueryPolicy>
1321 Query<QueryPolicy>::Query(Context* context, Expression<QueryPolicy>* expression,
1322 uint32 flags, port_id port, uint32 token)
1324 fContext(context),
1325 fExpression(expression),
1326 fCurrent(NULL),
1327 fIterator(NULL),
1328 fIndex(context),
1329 fFlags(flags),
1330 fPort(port),
1331 fToken(token),
1332 fNeedsEntry(false)
1334 // If the expression has a valid root pointer, the whole tree has
1335 // already passed the sanity check, so that we don't have to check
1336 // every pointer
1337 if (context == NULL || expression == NULL || expression->Root() == NULL)
1338 return;
1340 // create index on the stack and delete it afterwards
1341 fExpression->Root()->CalculateScore(fIndex);
1342 QueryPolicy::IndexUnset(fIndex);
1344 fNeedsEntry = fExpression->Root()->NeedsEntry();
1346 Rewind();
1350 template<typename QueryPolicy>
1351 Query<QueryPolicy>::~Query()
1353 delete fExpression;
1357 template<typename QueryPolicy>
1358 /*static*/ status_t
1359 Query<QueryPolicy>::Create(Context* context, const char* queryString,
1360 uint32 flags, port_id port, uint32 token, Query<QueryPolicy>*& _query)
1362 Expression<QueryPolicy>* expression
1363 = new(std::nothrow) Expression<QueryPolicy>((char*)queryString);
1364 if (expression == NULL)
1365 QUERY_RETURN_ERROR(B_NO_MEMORY);
1367 if (expression->InitCheck() != B_OK) {
1368 QUERY_INFORM("Could not parse query \"%s\", stopped at: \"%s\"\n",
1369 queryString, expression->Position());
1371 delete expression;
1372 QUERY_RETURN_ERROR(B_BAD_VALUE);
1375 Query<QueryPolicy>* query = new(std::nothrow) Query<QueryPolicy>(context,
1376 expression, flags, port, token);
1377 if (query == NULL) {
1378 delete expression;
1379 QUERY_RETURN_ERROR(B_NO_MEMORY);
1382 _query = query;
1383 return B_OK;
1387 template<typename QueryPolicy>
1388 status_t
1389 Query<QueryPolicy>::Rewind()
1391 // free previous stuff
1393 fStack.MakeEmpty();
1395 QueryPolicy::IndexIteratorDelete(fIterator);
1396 fIterator = NULL;
1397 fCurrent = NULL;
1399 // put the whole expression on the stack
1401 Stack<Term<QueryPolicy>*> stack;
1402 stack.Push(fExpression->Root());
1404 Term<QueryPolicy>* term;
1405 while (stack.Pop(&term)) {
1406 if (term->Op() < OP_EQUATION) {
1407 Operator<QueryPolicy>* op = (Operator<QueryPolicy>*)term;
1409 if (op->Op() == OP_OR) {
1410 stack.Push(op->Left());
1411 stack.Push(op->Right());
1412 } else {
1413 // For OP_AND, we can use the scoring system to decide which
1414 // path to add
1415 if (op->Right()->Score() > op->Left()->Score())
1416 stack.Push(op->Right());
1417 else
1418 stack.Push(op->Left());
1420 } else if (term->Op() == OP_EQUATION
1421 || fStack.Push((Equation<QueryPolicy>*)term) != B_OK)
1422 QUERY_FATAL("Unknown term on stack or stack error\n");
1425 return B_OK;
1429 template<typename QueryPolicy>
1430 status_t
1431 Query<QueryPolicy>::GetNextEntry(struct dirent* dirent, size_t size)
1433 if (fIterator != NULL)
1434 QueryPolicy::IndexIteratorResume(fIterator);
1436 status_t error = _GetNextEntry(dirent, size);
1438 if (fIterator != NULL)
1439 QueryPolicy::IndexIteratorSuspend(fIterator);
1441 return error;
1445 template<typename QueryPolicy>
1446 void
1447 Query<QueryPolicy>::LiveUpdate(Entry* entry, Node* node, const char* attribute,
1448 int32 type, const uint8* oldKey, size_t oldLength, const uint8* newKey,
1449 size_t newLength)
1451 if (fPort < 0 || fExpression == NULL || attribute == NULL)
1452 return;
1454 // TODO: check if the attribute is part of the query at all...
1456 // If no entry has been supplied, but the we need one for the evaluation
1457 // (i.e. the "name" attribute is used), we invoke ourselves for all entries
1458 // referring to the given node.
1459 if (entry == NULL && fNeedsEntry) {
1460 entry = QueryPolicy::NodeGetFirstReferrer(node);
1461 while (entry) {
1462 LiveUpdate(entry, node, attribute, type, oldKey, oldLength, newKey,
1463 newLength);
1464 entry = QueryPolicy::NodeGetNextReferrer(node, entry);
1466 return;
1469 status_t oldStatus = fExpression->Root()->Match(entry, node, attribute,
1470 type, oldKey, oldLength);
1471 status_t newStatus = fExpression->Root()->Match(entry, node, attribute,
1472 type, newKey, newLength);
1474 bool entryCreated = false;
1475 bool stillInQuery = false;
1477 if (oldStatus != MATCH_OK) {
1478 if (newStatus != MATCH_OK) {
1479 // nothing has changed
1480 return;
1482 entryCreated = true;
1483 } else if (newStatus != MATCH_OK) {
1484 // entry got removed
1485 entryCreated = false;
1486 } else if ((fFlags & B_ATTR_CHANGE_NOTIFICATION) != 0) {
1487 // The entry stays in the query
1488 stillInQuery = true;
1489 } else
1490 return;
1492 // notify query listeners
1493 status_t (*notify)(port_id, int32, dev_t, ino_t, const char*, ino_t);
1495 if (stillInQuery)
1496 notify = notify_query_attr_changed;
1497 else if (entryCreated)
1498 notify = notify_query_entry_created;
1499 else
1500 notify = notify_query_entry_removed;
1502 if (entry != NULL) {
1503 _SendEntryNotification(entry, notify);
1504 } else {
1505 entry = QueryPolicy::NodeGetFirstReferrer(node);
1506 while (entry) {
1507 _SendEntryNotification(entry, notify);
1508 entry = QueryPolicy::NodeGetNextReferrer(node, entry);
1514 template<typename QueryPolicy>
1515 void
1516 Query<QueryPolicy>::LiveUpdateRenameMove(Entry* entry, Node* node,
1517 ino_t oldDirectoryID, const char* oldName, size_t oldLength,
1518 ino_t newDirectoryID, const char* newName, size_t newLength)
1520 if (fPort < 0 || fExpression == NULL)
1521 return;
1523 // TODO: check if the attribute is part of the query at all...
1525 status_t oldStatus = fExpression->Root()->Match(entry, node, "name",
1526 B_STRING_TYPE, (const uint8*)oldName, oldLength);
1527 status_t newStatus = fExpression->Root()->Match(entry, node, "name",
1528 B_STRING_TYPE, (const uint8*)newName, newLength);
1530 if (oldStatus != MATCH_OK || oldStatus != newStatus)
1531 return;
1533 // The entry stays in the query, notify query listeners about the rename
1534 // or move
1536 // We send a notification for the given entry, if any, or otherwise for
1537 // all entries referring to the node;
1538 if (entry != NULL) {
1539 _SendEntryNotification(entry, notify_query_entry_removed);
1540 _SendEntryNotification(entry, notify_query_entry_created);
1541 } else {
1542 entry = QueryPolicy::NodeGetFirstReferrer(node);
1543 while (entry) {
1544 _SendEntryNotification(entry, notify_query_entry_removed);
1545 _SendEntryNotification(entry, notify_query_entry_created);
1546 entry = QueryPolicy::NodeGetNextReferrer(node, entry);
1552 template<typename QueryPolicy>
1553 status_t
1554 Query<QueryPolicy>::_GetNextEntry(struct dirent* dirent, size_t size)
1556 // If we don't have an equation to use yet/anymore, get a new one
1557 // from the stack
1558 while (true) {
1559 if (fIterator == NULL) {
1560 if (!fStack.Pop(&fCurrent)
1561 || fCurrent == NULL)
1562 return B_ENTRY_NOT_FOUND;
1564 status_t status = fCurrent->PrepareQuery(fContext, fIndex,
1565 &fIterator, fFlags & B_QUERY_NON_INDEXED);
1566 if (status == B_ENTRY_NOT_FOUND) {
1567 // try next equation
1568 continue;
1571 if (status != B_OK)
1572 return status;
1574 if (fCurrent == NULL)
1575 QUERY_RETURN_ERROR(B_ERROR);
1577 status_t status = fCurrent->GetNextMatching(fContext, fIterator, dirent,
1578 size);
1579 if (status != B_OK) {
1580 QueryPolicy::IndexIteratorDelete(fIterator);
1581 fIterator = NULL;
1582 fCurrent = NULL;
1583 } else {
1584 // only return if we have another entry
1585 return B_OK;
1591 template<typename QueryPolicy>
1592 void
1593 Query<QueryPolicy>::_SendEntryNotification(Entry* entry,
1594 status_t (*notify)(port_id, int32, dev_t, ino_t, const char*, ino_t))
1596 char nameBuffer[QueryPolicy::kMaxFileNameLength];
1597 const char* name = QueryPolicy::EntryGetNameNoCopy(entry, nameBuffer,
1598 sizeof(nameBuffer));
1599 if (name != NULL) {
1600 notify(fPort, fToken, QueryPolicy::ContextGetVolumeID(fContext),
1601 QueryPolicy::EntryGetParentID(entry), name,
1602 QueryPolicy::EntryGetNodeID(entry));
1607 } // namespace QueryParser
1610 #endif // _FILE_SYSTEMS_QUERY_PARSER_H