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