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