xref: /haiku/headers/private/file_systems/QueryParser.h (revision f73f5d4c42a01ece688cbb57b5d332cc0f68b2c6)
1 /*
2  * Copyright 2001-2009, 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
9 
10 
11 /*!	Query parsing and evaluation
12 
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.
16 */
17 
18 
19 // The parser has a very static design, but it will do what is required.
20 //
21 // ParseOr(), ParseAnd(), ParseEquation() are guarantying the operator
22 // precedence, that is =,!=,>,<,>=,<= .. && .. ||.
23 // Apparently, the "!" (not) can only be used with brackets.
24 //
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.
29 
30 
31 #include <dirent.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include <algorithm>
36 #include <new>
37 
38 #include <fs_interface.h>
39 #include <fs_query.h>
40 #include <TypeConstants.h>
41 
42 #include <util/SinglyLinkedList.h>
43 #include <util/Stack.h>
44 
45 #include <query_private.h>
46 
47 #include <lock.h>
48 
49 #include <file_systems/QueryParserUtils.h>
50 
51 
52 //#define DEBUG_QUERY
53 
54 #ifndef QUERY_RETURN_ERROR
55 #	define QUERY_RETURN_ERROR(error)	return (error)
56 #endif
57 
58 #ifndef QUERY_REPORT_ERROR
59 #	define QUERY_REPORT_ERROR(error)	do {} while (false)
60 #endif
61 
62 #ifndef QUERY_FATAL
63 #	define QUERY_FATAL(message...)		panic(message)
64 #endif
65 
66 #ifndef QUERY_INFORM
67 #	define QUERY_INFORM(message...)		dprintf(message)
68 #endif
69 
70 #ifndef QUERY_D
71 #	define QUERY_D(block)
72 #endif
73 
74 
75 namespace QueryParser {
76 
77 
78 template<typename QueryPolicy> class Equation;
79 template<typename QueryPolicy> class Expression;
80 template<typename QueryPolicy> class Term;
81 template<typename QueryPolicy> class Query;
82 
83 
84 enum ops {
85 	OP_NONE,
86 
87 	OP_AND,
88 	OP_OR,
89 
90 	OP_EQUATION,
91 		// is only used for invalid equations
92 
93 	OP_EQUAL,
94 	OP_UNEQUAL,
95 	OP_GREATER_THAN,
96 	OP_LESS_THAN,
97 	OP_GREATER_THAN_OR_EQUAL,
98 	OP_LESS_THAN_OR_EQUAL,
99 };
100 
101 
102 template<typename QueryPolicy>
103 union value {
104 	int64	Int64;
105 	uint64	Uint64;
106 	int32	Int32;
107 	uint32	Uint32;
108 	float	Float;
109 	double	Double;
110 	char	String[QueryPolicy::kMaxFileNameLength];
111 };
112 
113 
114 template<typename QueryPolicy>
115 class Query {
116 public:
117 			typedef typename QueryPolicy::Entry Entry;
118 			typedef typename QueryPolicy::Index Index;
119 			typedef typename QueryPolicy::IndexIterator IndexIterator;
120 			typedef typename QueryPolicy::Node Node;
121 			typedef typename QueryPolicy::Context Context;
122 
123 public:
124 							Query(Context* context,
125 								Expression<QueryPolicy>* expression,
126 								uint32 flags, port_id port, uint32 token);
127 							~Query();
128 
129 	static	status_t		Create(Context* context, const char* queryString,
130 								uint32 flags, port_id port, uint32 token,
131 								Query<QueryPolicy>*& _query);
132 
133 			status_t		Rewind();
134 	inline	status_t		GetNextEntry(struct dirent* dirent, size_t size);
135 
136 			void			LiveUpdate(Entry* entry, Node* node,
137 								const char* attribute, int32 type,
138 								const uint8* oldKey, size_t oldLength,
139 								const uint8* newKey, size_t newLength);
140 			void			LiveUpdateRenameMove(Entry* entry, Node* node,
141 								ino_t oldDirectoryID, const char* oldName,
142 								size_t oldLength, ino_t newDirectoryID,
143 								const char* newName, size_t newLength);
144 
145 			Expression<QueryPolicy>* GetExpression() const
146 								{ return fExpression; }
147 
148 			uint32			Flags() const
149 								{ return fFlags; }
150 
151 private:
152 			status_t		_GetNextEntry(struct dirent* dirent, size_t size);
153 			void			_SendEntryNotification(Entry* entry,
154 								status_t (*notify)(port_id, int32, dev_t, ino_t,
155 									const char*, ino_t));
156 
157 private:
158 			Context*		fContext;
159 			Expression<QueryPolicy>* fExpression;
160 			Equation<QueryPolicy>* fCurrent;
161 			IndexIterator*	fIterator;
162 			Index			fIndex;
163 			Stack<Equation<QueryPolicy>*> fStack;
164 
165 			uint32			fFlags;
166 			port_id			fPort;
167 			int32			fToken;
168 			bool			fNeedsEntry;
169 };
170 
171 
172 /*!	Abstract base class for the operator/equation classes.
173 */
174 template<typename QueryPolicy>
175 class Term {
176 public:
177 			typedef typename QueryPolicy::Entry Entry;
178 			typedef typename QueryPolicy::Index Index;
179 			typedef typename QueryPolicy::IndexIterator IndexIterator;
180 			typedef typename QueryPolicy::Node Node;
181 			typedef typename QueryPolicy::Context Context;
182 
183 public:
184 						Term(int8 op) : fOp(op), fParent(NULL) {}
185 	virtual				~Term() {}
186 
187 			int8		Op() const { return fOp; }
188 
189 			void		SetParent(Term<QueryPolicy>* parent)
190 							{ fParent = parent; }
191 			Term<QueryPolicy>* Parent() const { return fParent; }
192 
193 	virtual	status_t	Match(Entry* entry, Node* node,
194 							const char* attribute = NULL, int32 type = 0,
195 							const uint8* key = NULL, size_t size = 0) = 0;
196 	virtual	void		Complement() = 0;
197 
198 	virtual	void		CalculateScore(Index& index) = 0;
199 	virtual	int32		Score() const = 0;
200 
201 	virtual	status_t	InitCheck() = 0;
202 
203 	virtual	bool		NeedsEntry() = 0;
204 
205 #ifdef DEBUG_QUERY
206 	virtual	void		PrintToStream() = 0;
207 #endif
208 
209 protected:
210 			int8		fOp;
211 			Term<QueryPolicy>* fParent;
212 };
213 
214 
215 /*!	An Equation object represents an "attribute-equation operator-value" pair.
216 
217 	Although an Equation object is quite independent from the volume on which
218 	the query is run, there are some dependencies that are produced while
219 	querying:
220 	The type/size of the value, the score, and if it has an index or not.
221 	So you could run more than one query on the same volume, but it might return
222 	wrong values when it runs concurrently on another volume.
223 	That's not an issue right now, because we run single-threaded and don't use
224 	queries more than once.
225 */
226 template<typename QueryPolicy>
227 class Equation : public Term<QueryPolicy> {
228 public:
229 			typedef typename QueryPolicy::Entry Entry;
230 			typedef typename QueryPolicy::Index Index;
231 			typedef typename QueryPolicy::IndexIterator IndexIterator;
232 			typedef typename QueryPolicy::Node Node;
233 			typedef typename QueryPolicy::Context Context;
234 
235 public:
236 						Equation(char** expression);
237 	virtual				~Equation();
238 
239 	virtual	status_t	InitCheck();
240 
241 			status_t	ParseQuotedString(char** _start, char** _end);
242 			char*		CopyString(char* start, char* end);
243 
244 	virtual	status_t	Match(Entry* entry, Node* node,
245 							const char* attribute = NULL, int32 type = 0,
246 							const uint8* key = NULL, size_t size = 0);
247 	virtual void		Complement();
248 
249 			status_t	PrepareQuery(Context* context, Index& index,
250 							IndexIterator** iterator, bool queryNonIndexed);
251 			status_t	GetNextMatching(Context* context,
252 							IndexIterator* iterator, struct dirent* dirent,
253 							size_t bufferSize);
254 
255 	virtual	void		CalculateScore(Index &index);
256 	virtual	int32		Score() const { return fScore; }
257 
258 	virtual	bool		NeedsEntry();
259 
260 #ifdef DEBUG_QUERY
261 	virtual	void		PrintToStream();
262 #endif
263 
264 private:
265 						Equation(const Equation& other);
266 						Equation& operator=(const Equation& other);
267 							// no implementation
268 
269 			status_t	ConvertValue(type_code type);
270 			bool		CompareTo(const uint8* value, size_t size);
271 			uint8*		Value() const { return (uint8*)&fValue; }
272 			status_t	MatchEmptyString();
273 
274 			char*		fAttribute;
275 			char*		fString;
276 			union value<QueryPolicy> fValue;
277 			type_code	fType;
278 			size_t		fSize;
279 			bool		fIsPattern;
280 
281 			int32		fScore;
282 			bool		fHasIndex;
283 };
284 
285 
286 /*!	The Operator class does not represent a generic operator, but only those
287 	that combine two equations, namely "or", and "and".
288 */
289 template<typename QueryPolicy>
290 class Operator : public Term<QueryPolicy> {
291 public:
292 			typedef typename QueryPolicy::Entry Entry;
293 			typedef typename QueryPolicy::Index Index;
294 			typedef typename QueryPolicy::IndexIterator IndexIterator;
295 			typedef typename QueryPolicy::Node Node;
296 			typedef typename QueryPolicy::Context Context;
297 
298 public:
299 						Operator(Term<QueryPolicy>* left, int8 op,
300 							Term<QueryPolicy>* right);
301 	virtual				~Operator();
302 
303 			Term<QueryPolicy>* Left() const { return fLeft; }
304 			Term<QueryPolicy>* Right() const { return fRight; }
305 
306 	virtual	status_t	Match(Entry* entry, Node* node,
307 							const char* attribute = NULL, int32 type = 0,
308 							const uint8* key = NULL, size_t size = 0);
309 	virtual	void		Complement();
310 
311 	virtual	void		CalculateScore(Index& index);
312 	virtual	int32		Score() const;
313 
314 	virtual	status_t	InitCheck();
315 
316 	virtual	bool		NeedsEntry();
317 
318 #ifdef DEBUG_QUERY
319 	virtual	void		PrintToStream();
320 #endif
321 
322 private:
323 						Operator(const Operator& other);
324 						Operator& operator=(const Operator& other);
325 							// no implementation
326 
327 			Term<QueryPolicy>* fLeft;
328 			Term<QueryPolicy>* fRight;
329 };
330 
331 
332 template<typename QueryPolicy>
333 class Expression {
334 public:
335 			typedef typename QueryPolicy::Entry Entry;
336 			typedef typename QueryPolicy::Index Index;
337 			typedef typename QueryPolicy::IndexIterator IndexIterator;
338 			typedef typename QueryPolicy::Node Node;
339 			typedef typename QueryPolicy::Context Context;
340 
341 public:
342 							Expression(char* expr);
343 							~Expression();
344 
345 			status_t		InitCheck();
346 			const char*		Position() const { return fPosition; }
347 			Term<QueryPolicy>* Root() const { return fTerm; }
348 
349 protected:
350 			Term<QueryPolicy>* ParseOr(char** expr);
351 			Term<QueryPolicy>* ParseAnd(char** expr);
352 			Term<QueryPolicy>* ParseEquation(char** expr);
353 
354 			bool			IsOperator(char** expr, char op);
355 
356 private:
357 							Expression(const Expression& other);
358 							Expression& operator=(const Expression& other);
359 								// no implementation
360 
361 			char*			fPosition;
362 			Term<QueryPolicy>* fTerm;
363 };
364 
365 
366 //	#pragma mark -
367 
368 
369 template<typename QueryPolicy>
370 Equation<QueryPolicy>::Equation(char** expr)
371 	:
372 	Term<QueryPolicy>(OP_EQUATION),
373 	fAttribute(NULL),
374 	fString(NULL),
375 	fType(0),
376 	fIsPattern(false)
377 {
378 	char* string = *expr;
379 	char* start = string;
380 	char* end = NULL;
381 
382 	// Since the equation is the integral part of any query, we're just parsing
383 	// the whole thing here.
384 	// The whitespace at the start is already removed in
385 	// Expression::ParseEquation()
386 
387 	if (*start == '"' || *start == '\'') {
388 		// string is quoted (start has to be on the beginning of a string)
389 		if (ParseQuotedString(&start, &end) < B_OK)
390 			return;
391 
392 		// set string to a valid start of the equation symbol
393 		string = end + 2;
394 		skipWhitespace(&string);
395 		if (*string != '=' && *string != '<' && *string != '>'
396 			&& *string != '!') {
397 			*expr = string;
398 			return;
399 		}
400 	} else {
401 		// search the (in)equation for the actual equation symbol (and for other operators
402 		// in case the equation is malformed)
403 		while (*string && *string != '=' && *string != '<' && *string != '>'
404 			&& *string != '!' && *string != '&' && *string != '|') {
405 			string++;
406 		}
407 
408 		// get the attribute string	(and trim whitespace), in case
409 		// the string was not quoted
410 		end = string - 1;
411 		skipWhitespaceReverse(&end, start);
412 	}
413 
414 	// attribute string is empty (which is not allowed)
415 	if (start > end)
416 		return;
417 
418 	// At this point, "start" points to the beginning of the string, "end"
419 	// points to the last character of the string, and "string" points to the
420 	// first character of the equation symbol
421 
422 	// test for the right symbol (as this doesn't need any memory)
423 	switch (*string) {
424 		case '=':
425 			Term<QueryPolicy>::fOp = OP_EQUAL;
426 			break;
427 		case '>':
428 			Term<QueryPolicy>::fOp = *(string + 1) == '='
429 				? OP_GREATER_THAN_OR_EQUAL : OP_GREATER_THAN;
430 			break;
431 		case '<':
432 			Term<QueryPolicy>::fOp = *(string + 1) == '='
433 				? OP_LESS_THAN_OR_EQUAL : OP_LESS_THAN;
434 			break;
435 		case '!':
436 			if (*(string + 1) != '=')
437 				return;
438 			Term<QueryPolicy>::fOp = OP_UNEQUAL;
439 			break;
440 
441 		// any invalid characters will be rejected
442 		default:
443 			*expr = string;
444 			return;
445 	}
446 
447 	// lets change "start" to point to the first character after the symbol
448 	if (*(string + 1) == '=')
449 		string++;
450 	string++;
451 	skipWhitespace(&string);
452 
453 	// allocate & copy the attribute string
454 
455 	fAttribute = CopyString(start, end);
456 	if (fAttribute == NULL)
457 		return;
458 
459 	start = string;
460 	if (*start == '"' || *start == '\'') {
461 		// string is quoted (start has to be on the beginning of a string)
462 		if (ParseQuotedString(&start, &end) < B_OK)
463 			return;
464 
465 		string = end + 2;
466 		skipWhitespace(&string);
467 	} else {
468 		while (*string && *string != '&' && *string != '|' && *string != ')')
469 			string++;
470 
471 		end = string - 1;
472 		skipWhitespaceReverse(&end, start);
473 	}
474 
475 	// at this point, "start" will point to the first character of the value,
476 	// "end" will point to its last character, and "start" to the first non-
477 	// whitespace character after the value string
478 
479 	fString = CopyString(start, end);
480 	if (fString == NULL)
481 		return;
482 
483 	// patterns are only allowed for these operations (and strings)
484 	if (Term<QueryPolicy>::fOp == OP_EQUAL
485 		|| Term<QueryPolicy>::fOp == OP_UNEQUAL) {
486 		fIsPattern = isPattern(fString);
487 		if (fIsPattern && isValidPattern(fString) < B_OK) {
488 			// we only want to have valid patterns; setting fString
489 			// to NULL will cause InitCheck() to fail
490 			free(fString);
491 			fString = NULL;
492 		}
493 	}
494 
495 	*expr = string;
496 }
497 
498 
499 template<typename QueryPolicy>
500 Equation<QueryPolicy>::~Equation()
501 {
502 	free(fAttribute);
503 	free(fString);
504 }
505 
506 
507 template<typename QueryPolicy>
508 status_t
509 Equation<QueryPolicy>::InitCheck()
510 {
511 	if (fAttribute == NULL || fString == NULL
512 		|| Term<QueryPolicy>::fOp == OP_NONE) {
513 		return B_BAD_VALUE;
514 	}
515 
516 	return B_OK;
517 }
518 
519 
520 template<typename QueryPolicy>
521 status_t
522 Equation<QueryPolicy>::ParseQuotedString(char** _start, char** _end)
523 {
524 	char* start = *_start;
525 	char quote = *start++;
526 	char* end = start;
527 
528 	for (; *end && *end != quote; end++) {
529 		if (*end == '\\')
530 			end++;
531 	}
532 	if (*end == '\0')
533 		return B_BAD_VALUE;
534 
535 	*_start = start;
536 	*_end = end - 1;
537 
538 	return B_OK;
539 }
540 
541 
542 template<typename QueryPolicy>
543 char*
544 Equation<QueryPolicy>::CopyString(char* start, char* end)
545 {
546 	// end points to the last character of the string - and the length
547 	// also has to include the null-termination
548 	int32 length = end + 2 - start;
549 	// just to make sure; since that's the max. attribute name length and
550 	// the max. string in an index, it make sense to have it that way
551 	if (length > QueryPolicy::kMaxFileNameLength || length <= 0)
552 		return NULL;
553 
554 	char* copy = (char*)malloc(length);
555 	if (copy == NULL)
556 		return NULL;
557 
558 	memcpy(copy, start, length - 1);
559 	copy[length - 1] = '\0';
560 
561 	return copy;
562 }
563 
564 
565 template<typename QueryPolicy>
566 status_t
567 Equation<QueryPolicy>::ConvertValue(type_code type)
568 {
569 	// Has the type already been converted?
570 	if (type == fType)
571 		return B_OK;
572 
573 	char* string = fString;
574 
575 	switch (type) {
576 		case B_MIME_STRING_TYPE:
577 			type = B_STRING_TYPE;
578 			// supposed to fall through
579 		case B_STRING_TYPE:
580 			strncpy(fValue.String, string, QueryPolicy::kMaxFileNameLength);
581 			fValue.String[QueryPolicy::kMaxFileNameLength - 1] = '\0';
582 			fSize = strlen(fValue.String);
583 			break;
584 		case B_INT32_TYPE:
585 			fValue.Int32 = strtol(string, &string, 0);
586 			fSize = sizeof(int32);
587 			break;
588 		case B_UINT32_TYPE:
589 			fValue.Int32 = strtoul(string, &string, 0);
590 			fSize = sizeof(uint32);
591 			break;
592 		case B_INT64_TYPE:
593 			fValue.Int64 = strtoll(string, &string, 0);
594 			fSize = sizeof(int64);
595 			break;
596 		case B_UINT64_TYPE:
597 			fValue.Uint64 = strtoull(string, &string, 0);
598 			fSize = sizeof(uint64);
599 			break;
600 		case B_FLOAT_TYPE:
601 			fValue.Float = strtod(string, &string);
602 			fSize = sizeof(float);
603 			break;
604 		case B_DOUBLE_TYPE:
605 			fValue.Double = strtod(string, &string);
606 			fSize = sizeof(double);
607 			break;
608 		default:
609 			QUERY_FATAL("query value conversion to 0x%x requested!\n",
610 				(int)type);
611 			// should we fail here or just do a safety int32 conversion?
612 			return B_ERROR;
613 	}
614 
615 	fType = type;
616 
617 	// patterns are only allowed for string types
618 	if (fType != B_STRING_TYPE && fIsPattern)
619 		fIsPattern = false;
620 
621 	return B_OK;
622 }
623 
624 
625 /*!	Returns true when the key matches the equation. You have to
626 	call ConvertValue() before this one.
627 */
628 template<typename QueryPolicy>
629 bool
630 Equation<QueryPolicy>::CompareTo(const uint8* value, size_t size)
631 {
632 	int32 compare;
633 
634 	// fIsPattern is only true if it's a string type, and fOp OP_EQUAL, or
635 	// OP_UNEQUAL
636 	if (fIsPattern) {
637 		// we have already validated the pattern, so we don't check for failing
638 		// here - if something is broken, and matchString() returns an error,
639 		// we just don't match
640 		compare = matchString(fValue.String, (char*)value) == MATCH_OK ? 0 : 1;
641 	} else
642 		compare = compareKeys(fType, value, size, Value(), fSize);
643 
644 	switch (Term<QueryPolicy>::fOp) {
645 		case OP_EQUAL:
646 			return compare == 0;
647 		case OP_UNEQUAL:
648 			return compare != 0;
649 		case OP_LESS_THAN:
650 			return compare < 0;
651 		case OP_LESS_THAN_OR_EQUAL:
652 			return compare <= 0;
653 		case OP_GREATER_THAN:
654 			return compare > 0;
655 		case OP_GREATER_THAN_OR_EQUAL:
656 			return compare >= 0;
657 	}
658 	QUERY_FATAL("Unknown/Unsupported operation: %d\n", Term<QueryPolicy>::fOp);
659 	return false;
660 }
661 
662 
663 template<typename QueryPolicy>
664 void
665 Equation<QueryPolicy>::Complement()
666 {
667 	QUERY_D(if (fOp <= OP_EQUATION || fOp > OP_LESS_THAN_OR_EQUAL) {
668 		QUERY_FATAL("op out of range!\n");
669 		return;
670 	});
671 
672 	int8 complementOp[] = {OP_UNEQUAL, OP_EQUAL, OP_LESS_THAN_OR_EQUAL,
673 			OP_GREATER_THAN_OR_EQUAL, OP_LESS_THAN, OP_GREATER_THAN};
674 	Term<QueryPolicy>::fOp = complementOp[Term<QueryPolicy>::fOp - OP_EQUAL];
675 }
676 
677 
678 template<typename QueryPolicy>
679 status_t
680 Equation<QueryPolicy>::MatchEmptyString()
681 {
682 	// There is no matching attribute, we will just bail out if we
683 	// already know that our value is not of a string type.
684 	// If not, it will be converted to a string - and then be compared with "".
685 	// That's why we have to call ConvertValue() here - but it will be
686 	// a cheap call for the next time
687 	// TODO: Should we do this only for OP_UNEQUAL?
688 	if (fType != 0 && fType != B_STRING_TYPE)
689 		return NO_MATCH;
690 
691 	status_t status = ConvertValue(B_STRING_TYPE);
692 	if (status == B_OK)
693 		status = CompareTo((const uint8*)"", fSize) ? MATCH_OK : NO_MATCH;
694 
695 	return status;
696 }
697 
698 
699 /*!	Matches the node's attribute value with the equation.
700 	Returns MATCH_OK if it matches, NO_MATCH if not, < 0 if something went
701 	wrong.
702 */
703 template<typename QueryPolicy>
704 status_t
705 Equation<QueryPolicy>::Match(Entry* entry, Node* node,
706 	const char* attributeName, int32 type, const uint8* key, size_t size)
707 {
708 	// get a pointer to the attribute in question
709 	union value<QueryPolicy> value;
710 	uint8* buffer = (uint8*)&value;
711 	const size_t bufferSize = sizeof(value);
712 
713 	// first, check if we are matching for a live query and use that value
714 	if (attributeName != NULL && !strcmp(fAttribute, attributeName)) {
715 		if (key == NULL) {
716 			if (type == B_STRING_TYPE)
717 				return MatchEmptyString();
718 
719 			return NO_MATCH;
720 		}
721 		buffer = const_cast<uint8*>(key);
722 	} else if (!strcmp(fAttribute, "name")) {
723 		// if not, check for "fake" attributes ("name", "size", "last_modified")
724 		if (entry == NULL)
725 			return B_ERROR;
726 		buffer = (uint8*)QueryPolicy::EntryGetNameNoCopy(entry, buffer,
727 			sizeof(value));
728 		if (buffer == NULL)
729 			return B_ERROR;
730 
731 		type = B_STRING_TYPE;
732 		size = strlen((const char*)buffer);
733 	} else if (!strcmp(fAttribute, "size")) {
734 		value.Int64 = QueryPolicy::NodeGetSize(node);
735 		type = B_INT64_TYPE;
736 	} else if (!strcmp(fAttribute, "last_modified")) {
737 		value.Int32 = QueryPolicy::NodeGetLastModifiedTime(node);
738 		type = B_INT32_TYPE;
739 	} else {
740 		// then for attributes
741 		size = bufferSize;
742 		if (QueryPolicy::NodeGetAttribute(node, fAttribute, buffer, &size,
743 				&type) != B_OK) {
744 			return MatchEmptyString();
745 		}
746 	}
747 
748 	// prepare own value for use, if it is possible to convert it
749 	status_t status = ConvertValue(type);
750 	if (status == B_OK)
751 		status = CompareTo(buffer, size) ? MATCH_OK : NO_MATCH;
752 
753 	QUERY_RETURN_ERROR(status);
754 }
755 
756 
757 template<typename QueryPolicy>
758 void
759 Equation<QueryPolicy>::CalculateScore(Index &index)
760 {
761 	// As always, these values could be tuned and refined.
762 	// And the code could also need some real world testing :-)
763 
764 	// do we have to operate on a "foreign" index?
765 	if (Term<QueryPolicy>::fOp == OP_UNEQUAL
766 		|| QueryPolicy::IndexSetTo(index, fAttribute) < B_OK) {
767 		fScore = 0;
768 		return;
769 	}
770 
771 	// if we have a pattern, how much does it help our search?
772 	if (fIsPattern)
773 		fScore = getFirstPatternSymbol(fString) << 3;
774 	else {
775 		// Score by operator
776 		if (Term<QueryPolicy>::fOp == OP_EQUAL) {
777 			// higher than pattern="255 chars+*"
778 			fScore = 2048;
779 		} else {
780 			// the pattern search is regarded cheaper when you have at
781 			// least one character to set your index to
782 			fScore = 5;
783 		}
784 	}
785 
786 	// take index size into account
787 	fScore = QueryPolicy::IndexGetWeightedScore(index, fScore);
788 }
789 
790 
791 template<typename QueryPolicy>
792 status_t
793 Equation<QueryPolicy>::PrepareQuery(Context* /*context*/, Index& index,
794 	IndexIterator** iterator, bool queryNonIndexed)
795 {
796 	status_t status = QueryPolicy::IndexSetTo(index, fAttribute);
797 
798 	// if we should query attributes without an index, we can just proceed here
799 	if (status != B_OK && !queryNonIndexed)
800 		return B_ENTRY_NOT_FOUND;
801 
802 	type_code type;
803 
804 	// Special case for OP_UNEQUAL - it will always operate through the whole
805 	// index but we need the call to the original index to get the correct type
806 	if (status != B_OK || Term<QueryPolicy>::fOp == OP_UNEQUAL) {
807 		// Try to get an index that holds all files (name)
808 		// Also sets the default type for all attributes without index
809 		// to string.
810 		type = status < B_OK ? B_STRING_TYPE : QueryPolicy::IndexGetType(index);
811 
812 		if (QueryPolicy::IndexSetTo(index, "name") != B_OK)
813 			return B_ENTRY_NOT_FOUND;
814 
815 		fHasIndex = false;
816 	} else {
817 		fHasIndex = true;
818 		type = QueryPolicy::IndexGetType(index);
819 	}
820 
821 	if (ConvertValue(type) < B_OK)
822 		return B_BAD_VALUE;
823 
824 	*iterator = QueryPolicy::IndexCreateIterator(index);
825 	if (*iterator == NULL)
826 		return B_NO_MEMORY;
827 
828 	if ((Term<QueryPolicy>::fOp == OP_EQUAL
829 			|| Term<QueryPolicy>::fOp == OP_GREATER_THAN
830 			|| Term<QueryPolicy>::fOp == OP_GREATER_THAN_OR_EQUAL || fIsPattern)
831 		&& fHasIndex) {
832 		// set iterator to the exact position
833 
834 		int32 keySize = QueryPolicy::IndexGetKeySize(index);
835 
836 		// At this point, fIsPattern is only true if it's a string type, and fOp
837 		// is either OP_EQUAL or OP_UNEQUAL
838 		if (fIsPattern) {
839 			// let's see if we can use the beginning of the key for positioning
840 			// the iterator and adjust the key size; if not, just leave the
841 			// iterator at the start and return success
842 			keySize = getFirstPatternSymbol(fString);
843 			if (keySize <= 0)
844 				return B_OK;
845 		}
846 
847 		if (keySize == 0) {
848 			// B_STRING_TYPE doesn't have a fixed length, so it was set
849 			// to 0 before - we compute the correct value here
850 			if (fType == B_STRING_TYPE) {
851 				keySize = strlen(fValue.String);
852 
853 				// The empty string is a special case - we normally don't check
854 				// for the trailing null byte, in the case for the empty string
855 				// we do it explicitly, because there can't be keys in the
856 				// B+tree with a length of zero
857 				if (keySize == 0)
858 					keySize = 1;
859 			} else
860 				QUERY_RETURN_ERROR(B_ENTRY_NOT_FOUND);
861 		}
862 
863 		status = QueryPolicy::IndexIteratorFind(*iterator, Value(), keySize);
864 		if (Term<QueryPolicy>::fOp == OP_EQUAL && !fIsPattern)
865 			return status;
866 		else if (status == B_ENTRY_NOT_FOUND
867 			&& (fIsPattern || Term<QueryPolicy>::fOp == OP_GREATER_THAN
868 				|| Term<QueryPolicy>::fOp == OP_GREATER_THAN_OR_EQUAL))
869 			return B_OK;
870 
871 		QUERY_RETURN_ERROR(status);
872 	}
873 
874 	return B_OK;
875 }
876 
877 
878 template<typename QueryPolicy>
879 status_t
880 Equation<QueryPolicy>::GetNextMatching(Context* context,
881 	IndexIterator* iterator, struct dirent* dirent, size_t bufferSize)
882 {
883 	while (true) {
884 		union value<QueryPolicy> indexValue;
885 		size_t keyLength;
886 		Entry* entry = NULL;
887 
888 		status_t status = QueryPolicy::IndexIteratorGetNextEntry(iterator,
889 			&indexValue, &keyLength, (size_t)sizeof(indexValue), &entry);
890 		if (status != B_OK)
891 			return status;
892 
893 		// only compare against the index entry when this is the correct
894 		// index for the equation
895 		if (fHasIndex && !CompareTo((uint8*)&indexValue, keyLength)) {
896 			// They aren't equal? Let the operation decide what to do. Since
897 			// we always start at the beginning of the index (or the correct
898 			// position), only some needs to be stopped if the entry doesn't
899 			// fit.
900 			if (Term<QueryPolicy>::fOp == OP_LESS_THAN
901 				|| Term<QueryPolicy>::fOp == OP_LESS_THAN_OR_EQUAL
902 				|| (Term<QueryPolicy>::fOp == OP_EQUAL && !fIsPattern))
903 				return B_ENTRY_NOT_FOUND;
904 
905 			continue;
906 		}
907 
908 		// TODO: check user permissions here - but which one?!
909 		// we could filter out all those where we don't have
910 		// read access... (we should check for every parent
911 		// directory if the X_OK is allowed)
912 		// Although it's quite expensive to open all parents,
913 		// it's likely that the application that runs the
914 		// query will do something similar (and we don't have
915 		// to do it for root, either).
916 
917 		// go up in the tree until a &&-operator is found, and check if the
918 		// node matches with the rest of the expression - we don't have to
919 		// check ||-operators for that
920 		Term<QueryPolicy>* term = this;
921 		status = MATCH_OK;
922 
923 		if (!fHasIndex)
924 			status = Match(entry, QueryPolicy::EntryGetNode(entry));
925 
926 		while (term != NULL && status == MATCH_OK) {
927 			Operator<QueryPolicy>* parent
928 				= (Operator<QueryPolicy>*)term->Parent();
929 			if (parent == NULL)
930 				break;
931 
932 			if (parent->Op() == OP_AND) {
933 				// choose the other child of the parent
934 				Term<QueryPolicy>* other = parent->Right();
935 				if (other == term)
936 					other = parent->Left();
937 
938 				if (other == NULL) {
939 					QUERY_FATAL("&&-operator has only one child... "
940 						"(parent = %p)\n", parent);
941 					break;
942 				}
943 				status = other->Match(entry, QueryPolicy::EntryGetNode(entry));
944 				if (status < 0) {
945 					QUERY_REPORT_ERROR(status);
946 					status = NO_MATCH;
947 				}
948 			}
949 			term = (Term<QueryPolicy>*)parent;
950 		}
951 
952 		if (status == MATCH_OK) {
953 			ssize_t nameLength = QueryPolicy::EntryGetName(entry,
954 				dirent->d_name,
955 				(const char*)dirent + bufferSize - dirent->d_name);
956 			if (nameLength < 0)
957 				QUERY_RETURN_ERROR(nameLength);
958 
959 			dirent->d_dev = QueryPolicy::ContextGetVolumeID(context);
960 			dirent->d_ino = QueryPolicy::EntryGetNodeID(entry);
961 			dirent->d_pdev = dirent->d_dev;
962 			dirent->d_pino = QueryPolicy::EntryGetParentID(entry);
963 			dirent->d_reclen = sizeof(struct dirent) + strlen(dirent->d_name);
964 		}
965 
966 		if (status == MATCH_OK)
967 			return B_OK;
968 	}
969 	QUERY_RETURN_ERROR(B_ERROR);
970 }
971 
972 
973 template<typename QueryPolicy>
974 bool
975 Equation<QueryPolicy>::NeedsEntry()
976 {
977 	return strcmp(fAttribute, "name") == 0;
978 }
979 
980 
981 //	#pragma mark -
982 
983 
984 template<typename QueryPolicy>
985 Operator<QueryPolicy>::Operator(Term<QueryPolicy>* left, int8 op,
986 	Term<QueryPolicy>* right)
987 	:
988 	Term<QueryPolicy>(op),
989 	fLeft(left),
990 	fRight(right)
991 {
992 	if (left)
993 		left->SetParent(this);
994 	if (right)
995 		right->SetParent(this);
996 }
997 
998 
999 template<typename QueryPolicy>
1000 Operator<QueryPolicy>::~Operator()
1001 {
1002 	delete fLeft;
1003 	delete fRight;
1004 }
1005 
1006 
1007 template<typename QueryPolicy>
1008 status_t
1009 Operator<QueryPolicy>::Match(Entry* entry, Node* node, const char* attribute,
1010 	int32 type, const uint8* key, size_t size)
1011 {
1012 	if (Term<QueryPolicy>::fOp == OP_AND) {
1013 		status_t status = fLeft->Match(entry, node, attribute, type, key,
1014 			size);
1015 		if (status != MATCH_OK)
1016 			return status;
1017 
1018 		return fRight->Match(entry, node, attribute, type, key, size);
1019 	} else {
1020 		// choose the term with the better score for OP_OR
1021 		Term<QueryPolicy>* first;
1022 		Term<QueryPolicy>* second;
1023 		if (fRight->Score() > fLeft->Score()) {
1024 			first = fLeft;
1025 			second = fRight;
1026 		} else {
1027 			first = fRight;
1028 			second = fLeft;
1029 		}
1030 
1031 		status_t status = first->Match(entry, node, attribute, type, key,
1032 			size);
1033 		if (status != NO_MATCH)
1034 			return status;
1035 
1036 		return second->Match(entry, node, attribute, type, key, size);
1037 	}
1038 }
1039 
1040 
1041 template<typename QueryPolicy>
1042 void
1043 Operator<QueryPolicy>::Complement()
1044 {
1045 	if (Term<QueryPolicy>::fOp == OP_AND)
1046 		Term<QueryPolicy>::fOp = OP_OR;
1047 	else
1048 		Term<QueryPolicy>::fOp = OP_AND;
1049 
1050 	fLeft->Complement();
1051 	fRight->Complement();
1052 }
1053 
1054 
1055 template<typename QueryPolicy>
1056 void
1057 Operator<QueryPolicy>::CalculateScore(Index &index)
1058 {
1059 	fLeft->CalculateScore(index);
1060 	fRight->CalculateScore(index);
1061 }
1062 
1063 
1064 template<typename QueryPolicy>
1065 int32
1066 Operator<QueryPolicy>::Score() const
1067 {
1068 	if (Term<QueryPolicy>::fOp == OP_AND) {
1069 		// return the one with the better score
1070 		if (fRight->Score() > fLeft->Score())
1071 			return fRight->Score();
1072 
1073 		return fLeft->Score();
1074 	}
1075 
1076 	// for OP_OR, be honest, and return the one with the worse score
1077 	if (fRight->Score() < fLeft->Score())
1078 		return fRight->Score();
1079 
1080 	return fLeft->Score();
1081 }
1082 
1083 
1084 template<typename QueryPolicy>
1085 status_t
1086 Operator<QueryPolicy>::InitCheck()
1087 {
1088 	if ((Term<QueryPolicy>::fOp != OP_AND && Term<QueryPolicy>::fOp != OP_OR)
1089 		|| fLeft == NULL || fLeft->InitCheck() < B_OK
1090 		|| fRight == NULL || fRight->InitCheck() < B_OK)
1091 		return B_ERROR;
1092 
1093 	return B_OK;
1094 }
1095 
1096 
1097 template<typename QueryPolicy>
1098 bool
1099 Operator<QueryPolicy>::NeedsEntry()
1100 {
1101 	return ((fLeft && fLeft->NeedsEntry()) || (fRight && fRight->NeedsEntry()));
1102 }
1103 
1104 
1105 //	#pragma mark -
1106 
1107 #ifdef DEBUG_QUERY
1108 
1109 template<typename QueryPolicy>
1110 void
1111 Operator<QueryPolicy>::PrintToStream()
1112 {
1113 	QUERY_D(__out("( "));
1114 	if (fLeft != NULL)
1115 		fLeft->PrintToStream();
1116 
1117 	const char* op;
1118 	switch (Term<QueryPolicy>::fOp) {
1119 		case OP_OR: op = "OR"; break;
1120 		case OP_AND: op = "AND"; break;
1121 		default: op = "?"; break;
1122 	}
1123 	QUERY_D(__out(" %s ", op));
1124 
1125 	if (fRight != NULL)
1126 		fRight->PrintToStream();
1127 
1128 	QUERY_D(__out(" )"));
1129 }
1130 
1131 
1132 template<typename QueryPolicy>
1133 void
1134 Equation<QueryPolicy>::PrintToStream()
1135 {
1136 	const char* symbol = "???";
1137 	switch (Term<QueryPolicy>::fOp) {
1138 		case OP_EQUAL: symbol = "=="; break;
1139 		case OP_UNEQUAL: symbol = "!="; break;
1140 		case OP_GREATER_THAN: symbol = ">"; break;
1141 		case OP_GREATER_THAN_OR_EQUAL: symbol = ">="; break;
1142 		case OP_LESS_THAN: symbol = "<"; break;
1143 		case OP_LESS_THAN_OR_EQUAL: symbol = "<="; break;
1144 	}
1145 	QUERY_D(__out("[\"%s\" %s \"%s\"]", fAttribute, symbol, fString));
1146 }
1147 
1148 #endif	// DEBUG_QUERY
1149 
1150 //	#pragma mark -
1151 
1152 
1153 template<typename QueryPolicy>
1154 Expression<QueryPolicy>::Expression(char* expr)
1155 {
1156 	if (expr == NULL)
1157 		return;
1158 
1159 	fTerm = ParseOr(&expr);
1160 	if (fTerm != NULL && fTerm->InitCheck() < B_OK) {
1161 		QUERY_FATAL("Corrupt tree in expression!\n");
1162 		delete fTerm;
1163 		fTerm = NULL;
1164 	}
1165 	QUERY_D(if (fTerm != NULL) {
1166 		fTerm->PrintToStream();
1167 		QUERY_D(__out("\n"));
1168 		if (*expr != '\0')
1169 			PRINT(("Unexpected end of string: \"%s\"!\n", expr));
1170 	});
1171 	fPosition = expr;
1172 }
1173 
1174 
1175 template<typename QueryPolicy>
1176 Expression<QueryPolicy>::~Expression()
1177 {
1178 	delete fTerm;
1179 }
1180 
1181 
1182 template<typename QueryPolicy>
1183 Term<QueryPolicy>*
1184 Expression<QueryPolicy>::ParseEquation(char** expr)
1185 {
1186 	skipWhitespace(expr);
1187 
1188 	bool _not = false;
1189 	if (**expr == '!') {
1190 		skipWhitespace(expr, 1);
1191 		if (**expr != '(')
1192 			return NULL;
1193 
1194 		_not = true;
1195 	}
1196 
1197 	if (**expr == ')') {
1198 		// shouldn't be handled here
1199 		return NULL;
1200 	} else if (**expr == '(') {
1201 		skipWhitespace(expr, 1);
1202 
1203 		Term<QueryPolicy>* term = ParseOr(expr);
1204 
1205 		skipWhitespace(expr);
1206 
1207 		if (**expr != ')') {
1208 			delete term;
1209 			return NULL;
1210 		}
1211 
1212 		// If the term is negated, we just complement the tree, to get
1213 		// rid of the not, a.k.a. DeMorgan's Law.
1214 		if (_not)
1215 			term->Complement();
1216 
1217 		skipWhitespace(expr, 1);
1218 
1219 		return term;
1220 	}
1221 
1222 	Equation<QueryPolicy>* equation
1223 		= new(std::nothrow) Equation<QueryPolicy>(expr);
1224 	if (equation == NULL || equation->InitCheck() < B_OK) {
1225 		delete equation;
1226 		return NULL;
1227 	}
1228 	return equation;
1229 }
1230 
1231 
1232 template<typename QueryPolicy>
1233 Term<QueryPolicy>*
1234 Expression<QueryPolicy>::ParseAnd(char** expr)
1235 {
1236 	Term<QueryPolicy>* left = ParseEquation(expr);
1237 	if (left == NULL)
1238 		return NULL;
1239 
1240 	while (IsOperator(expr, '&')) {
1241 		Term<QueryPolicy>* right = ParseAnd(expr);
1242 		Term<QueryPolicy>* newParent = NULL;
1243 
1244 		if (right == NULL
1245 			|| (newParent = new(std::nothrow) Operator<QueryPolicy>(left,
1246 				OP_AND, right)) == NULL) {
1247 			delete left;
1248 			delete right;
1249 
1250 			return NULL;
1251 		}
1252 		left = newParent;
1253 	}
1254 
1255 	return left;
1256 }
1257 
1258 
1259 template<typename QueryPolicy>
1260 Term<QueryPolicy>*
1261 Expression<QueryPolicy>::ParseOr(char** expr)
1262 {
1263 	Term<QueryPolicy>* left = ParseAnd(expr);
1264 	if (left == NULL)
1265 		return NULL;
1266 
1267 	while (IsOperator(expr, '|')) {
1268 		Term<QueryPolicy>* right = ParseAnd(expr);
1269 		Term<QueryPolicy>* newParent = NULL;
1270 
1271 		if (right == NULL
1272 			|| (newParent = new(std::nothrow) Operator<QueryPolicy>(left, OP_OR,
1273 				right)) == NULL) {
1274 			delete left;
1275 			delete right;
1276 
1277 			return NULL;
1278 		}
1279 		left = newParent;
1280 	}
1281 
1282 	return left;
1283 }
1284 
1285 
1286 template<typename QueryPolicy>
1287 bool
1288 Expression<QueryPolicy>::IsOperator(char** expr, char op)
1289 {
1290 	char* string = *expr;
1291 
1292 	if (*string == op && *(string + 1) == op) {
1293 		*expr += 2;
1294 		return true;
1295 	}
1296 	return false;
1297 }
1298 
1299 
1300 template<typename QueryPolicy>
1301 status_t
1302 Expression<QueryPolicy>::InitCheck()
1303 {
1304 	if (fTerm == NULL)
1305 		return B_BAD_VALUE;
1306 
1307 	return B_OK;
1308 }
1309 
1310 
1311 //	#pragma mark -
1312 
1313 
1314 template<typename QueryPolicy>
1315 Query<QueryPolicy>::Query(Context* context, Expression<QueryPolicy>* expression,
1316 	uint32 flags, port_id port, uint32 token)
1317 	:
1318 	fContext(context),
1319 	fExpression(expression),
1320 	fCurrent(NULL),
1321 	fIterator(NULL),
1322 	fIndex(context),
1323 	fFlags(flags),
1324 	fPort(port),
1325 	fToken(token),
1326 	fNeedsEntry(false)
1327 {
1328 	// If the expression has a valid root pointer, the whole tree has
1329 	// already passed the sanity check, so that we don't have to check
1330 	// every pointer
1331 	if (context == NULL || expression == NULL || expression->Root() == NULL)
1332 		return;
1333 
1334 	// create index on the stack and delete it afterwards
1335 	fExpression->Root()->CalculateScore(fIndex);
1336 	QueryPolicy::IndexUnset(fIndex);
1337 
1338 	fNeedsEntry = fExpression->Root()->NeedsEntry();
1339 
1340 	Rewind();
1341 }
1342 
1343 
1344 template<typename QueryPolicy>
1345 Query<QueryPolicy>::~Query()
1346 {
1347 	delete fExpression;
1348 }
1349 
1350 
1351 template<typename QueryPolicy>
1352 /*static*/ status_t
1353 Query<QueryPolicy>::Create(Context* context, const char* queryString,
1354 	uint32 flags, port_id port, uint32 token, Query<QueryPolicy>*& _query)
1355 {
1356 	Expression<QueryPolicy>* expression
1357 		= new(std::nothrow) Expression<QueryPolicy>((char*)queryString);
1358 	if (expression == NULL)
1359 		QUERY_RETURN_ERROR(B_NO_MEMORY);
1360 
1361 	if (expression->InitCheck() != B_OK) {
1362 		QUERY_INFORM("Could not parse query \"%s\", stopped at: \"%s\"\n",
1363 			queryString, expression->Position());
1364 
1365 		delete expression;
1366 		QUERY_RETURN_ERROR(B_BAD_VALUE);
1367 	}
1368 
1369 	Query<QueryPolicy>* query = new(std::nothrow) Query<QueryPolicy>(context,
1370 		expression, flags, port, token);
1371 	if (query == NULL) {
1372 		delete expression;
1373 		QUERY_RETURN_ERROR(B_NO_MEMORY);
1374 	}
1375 
1376 	_query = query;
1377 	return B_OK;
1378 }
1379 
1380 
1381 template<typename QueryPolicy>
1382 status_t
1383 Query<QueryPolicy>::Rewind()
1384 {
1385 	// free previous stuff
1386 
1387 	fStack.MakeEmpty();
1388 
1389 	QueryPolicy::IndexIteratorDelete(fIterator);
1390 	fIterator = NULL;
1391 	fCurrent = NULL;
1392 
1393 	// put the whole expression on the stack
1394 
1395 	Stack<Term<QueryPolicy>*> stack;
1396 	stack.Push(fExpression->Root());
1397 
1398 	Term<QueryPolicy>* term;
1399 	while (stack.Pop(&term)) {
1400 		if (term->Op() < OP_EQUATION) {
1401 			Operator<QueryPolicy>* op = (Operator<QueryPolicy>*)term;
1402 
1403 			if (op->Op() == OP_OR) {
1404 				stack.Push(op->Left());
1405 				stack.Push(op->Right());
1406 			} else {
1407 				// For OP_AND, we can use the scoring system to decide which
1408 				// path to add
1409 				if (op->Right()->Score() > op->Left()->Score())
1410 					stack.Push(op->Right());
1411 				else
1412 					stack.Push(op->Left());
1413 			}
1414 		} else if (term->Op() == OP_EQUATION
1415 			|| fStack.Push((Equation<QueryPolicy>*)term) != B_OK)
1416 			QUERY_FATAL("Unknown term on stack or stack error\n");
1417 	}
1418 
1419 	return B_OK;
1420 }
1421 
1422 
1423 template<typename QueryPolicy>
1424 status_t
1425 Query<QueryPolicy>::GetNextEntry(struct dirent* dirent, size_t size)
1426 {
1427 	if (fIterator != NULL)
1428 		QueryPolicy::IndexIteratorResume(fIterator);
1429 
1430 	status_t error = _GetNextEntry(dirent, size);
1431 
1432 	if (fIterator != NULL)
1433 		QueryPolicy::IndexIteratorSuspend(fIterator);
1434 
1435 	return error;
1436 }
1437 
1438 
1439 template<typename QueryPolicy>
1440 void
1441 Query<QueryPolicy>::LiveUpdate(Entry* entry, Node* node, const char* attribute,
1442 	int32 type, const uint8* oldKey, size_t oldLength, const uint8* newKey,
1443 	size_t newLength)
1444 {
1445 	if (fPort < 0 || fExpression == NULL || attribute == NULL)
1446 		return;
1447 
1448 	// TODO: check if the attribute is part of the query at all...
1449 
1450 	// If no entry has been supplied, but the we need one for the evaluation
1451 	// (i.e. the "name" attribute is used), we invoke ourselves for all entries
1452 	// referring to the given node.
1453 	if (entry == NULL && fNeedsEntry) {
1454 		entry = QueryPolicy::NodeGetFirstReferrer(node);
1455 		while (entry) {
1456 			LiveUpdate(entry, node, attribute, type, oldKey, oldLength, newKey,
1457 				newLength);
1458 			entry = QueryPolicy::NodeGetNextReferrer(node, entry);
1459 		}
1460 		return;
1461 	}
1462 
1463 	status_t oldStatus = fExpression->Root()->Match(entry, node, attribute,
1464 		type, oldKey, oldLength);
1465 	status_t newStatus = fExpression->Root()->Match(entry, node, attribute,
1466 		type, newKey, newLength);
1467 
1468 	bool entryCreated = false;
1469 	bool stillInQuery = false;
1470 
1471 	if (oldStatus != MATCH_OK) {
1472 		if (newStatus != MATCH_OK) {
1473 			// nothing has changed
1474 			return;
1475 		}
1476 		entryCreated = true;
1477 	} else if (newStatus != MATCH_OK) {
1478 		// entry got removed
1479 		entryCreated = false;
1480 	} else if ((fFlags & B_ATTR_CHANGE_NOTIFICATION) != 0) {
1481 		// The entry stays in the query
1482 		stillInQuery = true;
1483 	} else
1484 		return;
1485 
1486 	// notify query listeners
1487 	status_t (*notify)(port_id, int32, dev_t, ino_t, const char*, ino_t);
1488 
1489 	if (stillInQuery)
1490 		notify = notify_query_attr_changed;
1491 	else if (entryCreated)
1492 		notify = notify_query_entry_created;
1493 	else
1494 		notify = notify_query_entry_removed;
1495 
1496 	if (entry != NULL) {
1497 		_SendEntryNotification(entry, notify);
1498 	} else {
1499 		entry = QueryPolicy::NodeGetFirstReferrer(node);
1500 		while (entry) {
1501 			_SendEntryNotification(entry, notify);
1502 			entry = QueryPolicy::NodeGetNextReferrer(node, entry);
1503 		}
1504 	}
1505 }
1506 
1507 
1508 template<typename QueryPolicy>
1509 void
1510 Query<QueryPolicy>::LiveUpdateRenameMove(Entry* entry, Node* node,
1511 	ino_t oldDirectoryID, const char* oldName, size_t oldLength,
1512 	ino_t newDirectoryID, const char* newName, size_t newLength)
1513 {
1514 	if (fPort < 0 || fExpression == NULL)
1515 		return;
1516 
1517 	// TODO: check if the attribute is part of the query at all...
1518 
1519 	status_t oldStatus = fExpression->Root()->Match(entry, node, "name",
1520 		B_STRING_TYPE, (const uint8*)oldName, oldLength);
1521 	status_t newStatus = fExpression->Root()->Match(entry, node, "name",
1522 		B_STRING_TYPE, (const uint8*)newName, newLength);
1523 
1524 	if (oldStatus != MATCH_OK || oldStatus != newStatus)
1525 		return;
1526 
1527 	// The entry stays in the query, notify query listeners about the rename
1528 	// or move
1529 
1530 	// We send a notification for the given entry, if any, or otherwise for
1531 	// all entries referring to the node;
1532 	if (entry != NULL) {
1533 		_SendEntryNotification(entry, notify_query_entry_removed);
1534 		_SendEntryNotification(entry, notify_query_entry_created);
1535 	} else {
1536 		entry = QueryPolicy::NodeGetFirstReferrer(node);
1537 		while (entry) {
1538 			_SendEntryNotification(entry, notify_query_entry_removed);
1539 			_SendEntryNotification(entry, notify_query_entry_created);
1540 			entry = QueryPolicy::NodeGetNextReferrer(node, entry);
1541 		}
1542 	}
1543 }
1544 
1545 
1546 template<typename QueryPolicy>
1547 status_t
1548 Query<QueryPolicy>::_GetNextEntry(struct dirent* dirent, size_t size)
1549 {
1550 	// If we don't have an equation to use yet/anymore, get a new one
1551 	// from the stack
1552 	while (true) {
1553 		if (fIterator == NULL) {
1554 			if (!fStack.Pop(&fCurrent)
1555 				|| fCurrent == NULL)
1556 				return B_ENTRY_NOT_FOUND;
1557 
1558 			status_t status = fCurrent->PrepareQuery(fContext, fIndex,
1559 				&fIterator, fFlags & B_QUERY_NON_INDEXED);
1560 			if (status == B_ENTRY_NOT_FOUND) {
1561 				// try next equation
1562 				continue;
1563 			}
1564 
1565 			if (status != B_OK)
1566 				return status;
1567 		}
1568 		if (fCurrent == NULL)
1569 			QUERY_RETURN_ERROR(B_ERROR);
1570 
1571 		status_t status = fCurrent->GetNextMatching(fContext, fIterator, dirent,
1572 			size);
1573 		if (status != B_OK) {
1574 			QueryPolicy::IndexIteratorDelete(fIterator);
1575 			fIterator = NULL;
1576 			fCurrent = NULL;
1577 		} else {
1578 			// only return if we have another entry
1579 			return B_OK;
1580 		}
1581 	}
1582 }
1583 
1584 
1585 template<typename QueryPolicy>
1586 void
1587 Query<QueryPolicy>::_SendEntryNotification(Entry* entry,
1588 	status_t (*notify)(port_id, int32, dev_t, ino_t, const char*, ino_t))
1589 {
1590 	char nameBuffer[QueryPolicy::kMaxFileNameLength];
1591 	const char* name = QueryPolicy::EntryGetNameNoCopy(entry, nameBuffer,
1592 		sizeof(nameBuffer));
1593 	if (name != NULL) {
1594 		notify(fPort, fToken, QueryPolicy::ContextGetVolumeID(fContext),
1595 			QueryPolicy::EntryGetParentID(entry), name,
1596 			QueryPolicy::EntryGetNodeID(entry));
1597 	}
1598 }
1599 
1600 
1601 }	// namespace QueryParser
1602 
1603 
1604 #endif	// _FILE_SYSTEMS_QUERY_PARSER_H
1605